TheCard handling in messages
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "Unknown",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "Save",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "Cannot parse vCard file.",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "Chat",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "Find",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +175,10 @@
|
||||
"defaultMessage": "Cannot initiate file upload.",
|
||||
"description": "Generic error messagewhen attachment fails"
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed"
|
||||
},
|
||||
"change_email": {
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email"
|
||||
@@ -207,6 +211,10 @@
|
||||
"defaultMessage": "Ignore",
|
||||
"description": "Action [Ignore] for chat invitation."
|
||||
},
|
||||
"chat_now": {
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card"
|
||||
},
|
||||
"clear_messages_warning": {
|
||||
"defaultMessage": "Are you sure you want to clear all messages? It cannot be undone.",
|
||||
"description": "Alert dialog warning when deleting all messages."
|
||||
@@ -327,6 +335,10 @@
|
||||
"defaultMessage": "The file size {size} exceeds the {limit} limit.",
|
||||
"description": "Error message when attachment is too large"
|
||||
},
|
||||
"find_user": {
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card"
|
||||
},
|
||||
"forgot_password_link": {
|
||||
"defaultMessage": "Forgot password?",
|
||||
"description": "Link to Reset password form"
|
||||
@@ -880,6 +892,10 @@
|
||||
"defaultMessage": "Requested",
|
||||
"description": "Title for permissions"
|
||||
},
|
||||
"save_action": {
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button"
|
||||
},
|
||||
"save_attachment": {
|
||||
"defaultMessage": "save",
|
||||
"description": "Call to save an attachment"
|
||||
@@ -1056,6 +1072,10 @@
|
||||
"defaultMessage": "Freeform name of the group",
|
||||
"description": "Prompt for entering topic name"
|
||||
},
|
||||
"unknown_name": {
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing"
|
||||
},
|
||||
"unnamed_topic": {
|
||||
"defaultMessage": "Unnamed",
|
||||
"description": "Title shown when the topic has no name"
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,5 +1906,40 @@
|
||||
"description": "Label [Scan my ID:]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"unknown_name": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Unknown",
|
||||
"description": "Name to show when the name is missing",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"save_action": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Save",
|
||||
"description": "Label for Save button",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"cannot_parse_vcard": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Cannot parse vCard file.",
|
||||
"description": "Error message when vCard file cannot be parsed",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"chat_now": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Chat",
|
||||
"description": "Label for message button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"find_user": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Find",
|
||||
"description": "Label for search button in contact card",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+24
-11
@@ -1,13 +1,14 @@
|
||||
import React from 'react';
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
import { Drafty } from 'tinode-sdk';
|
||||
import { Drafty, TheCard } from 'tinode-sdk';
|
||||
|
||||
import AudioPlayer from '../widgets/audio-player.jsx'
|
||||
import CallMessage from '../widgets/call-message.jsx'
|
||||
import CallStatus from '../widgets/call-status.jsx';
|
||||
import InlineVideo from '../widgets/inline-video.jsx';
|
||||
import LazyImage from '../widgets/lazy-image.jsx'
|
||||
import LazyImage from '../widgets/lazy-image.jsx';
|
||||
import TheCardViewer from '../widgets/the-card-viewer.jsx';
|
||||
import UploadingImage from '../widgets/uploading-image.jsx'
|
||||
|
||||
import { BROKEN_IMAGE_SIZE, CLICKABLE_URL_SCHEMES, IMAGE_THUMBNAIL_DIM, NO_DIMENSIONS_VIDEO,
|
||||
@@ -48,10 +49,7 @@ const messages = defineMessages({
|
||||
// 'this' must contain:
|
||||
// viewportWidth:
|
||||
// authorizeURL:
|
||||
// onImagePreview:
|
||||
// onVideoPreview:
|
||||
// onFormButtonClick:
|
||||
// onQuoteClick:
|
||||
// onHandleClick:
|
||||
export function fullFormatter(style, data, values, key, stack) {
|
||||
if (stack.includes('QQ')) {
|
||||
return quoteFormatter.call(this, style, data, values, key);
|
||||
@@ -100,7 +98,7 @@ export function fullFormatter(style, data, values, key, stack) {
|
||||
break;
|
||||
case 'BN':
|
||||
// Button
|
||||
attr.onClick = this.onFormButtonClick;
|
||||
attr.onClick = (e) => this.onHandleClick(e, 'form_button');
|
||||
let inner = React.Children.map(values, (child) => {
|
||||
return typeof child == 'string' ? child : undefined;
|
||||
});
|
||||
@@ -133,7 +131,16 @@ export function fullFormatter(style, data, values, key, stack) {
|
||||
case 'QQ':
|
||||
// Quote/citation.
|
||||
attr.className = 'reply-quote'
|
||||
attr.onClick = this.onQuoteClick;
|
||||
attr.onClick = (e) => this.onHandleClick(e, 'quote');
|
||||
break;
|
||||
case 'TC':
|
||||
// TheCard
|
||||
el = TheCardViewer;
|
||||
attr.content = data;
|
||||
attr.authorizeURL = this.authorizeURL;
|
||||
attr.onChatClick = (e) => this.onHandleClick(e, 'contact_chat');
|
||||
attr.onFindClick = (e) => this.onHandleClick(e, 'contact_find');
|
||||
values = null;
|
||||
break;
|
||||
case 'VC':
|
||||
el = CallMessage;
|
||||
@@ -200,7 +207,7 @@ function handleImageData(el, data, attr) {
|
||||
if (attr.src) {
|
||||
if (Math.max(data.width || 0, data.height || 0) > IMAGE_THUMBNAIL_DIM) {
|
||||
// Allow previews for large enough images.
|
||||
attr.onClick = this.onImagePreview;
|
||||
attr.onClick = (e) => this.onHandleClick(e, 'image');
|
||||
attr.className += ' image-clickable';
|
||||
}
|
||||
attr.loading = 'lazy';
|
||||
@@ -241,7 +248,7 @@ function handleVideoData(el, data, attr) {
|
||||
attr.src = this.authorizeURL(sanitizeUrlForMime(attr.src, 'image'));
|
||||
attr.alt = data.name;
|
||||
if (data.ref || data.val) {
|
||||
attr.onClick = this.onVideoPreview;
|
||||
attr.onClick = (e) => this.onHandleClick(e, 'video');
|
||||
attr.loading = 'lazy';
|
||||
}
|
||||
el = InlineVideo;
|
||||
@@ -329,6 +336,12 @@ export function previewFormatter(style, data, values, key) {
|
||||
el = null;
|
||||
values = null;
|
||||
break;
|
||||
case 'TC':
|
||||
// TheCard
|
||||
el = React.Fragment;
|
||||
values = [<i key="tc" className="material-icons">contact_mail</i>, ' ',
|
||||
TheCard.getFn(data) || this.formatMessage(messages.drafty_unknown)];
|
||||
break;
|
||||
case 'VD':
|
||||
// Replace image with '[icon] Video'.
|
||||
el = React.Fragment;
|
||||
@@ -392,7 +405,7 @@ function inlineVideoAttr(attr, data) {
|
||||
// formatMessage: this.props.intl.formatMessage
|
||||
// messages: formatjs messages defined with defineMessages.
|
||||
// authorizeURL: this.props.tinode.authorizeURL
|
||||
// onQuoteClick: this.handleQuoteClick (optional)
|
||||
// onHandleClick: this.handleDraftyClick
|
||||
function quoteFormatter(style, data, values, key) {
|
||||
if (['BR', 'EX', 'IM', 'MN', 'VD'].includes(style)) {
|
||||
let el = Drafty.tagName(style);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import { Drafty, Tinode } from 'tinode-sdk';
|
||||
import { Drafty, Tinode, TheCard } from 'tinode-sdk';
|
||||
|
||||
import CallPanel from '../widgets/call-panel.jsx';
|
||||
import ChatMessage from '../widgets/chat-message.jsx';
|
||||
@@ -104,6 +104,11 @@ const messages = defineMessages({
|
||||
'other {{count, number} members}}',
|
||||
description: 'Count of group topic members'
|
||||
},
|
||||
cannot_parse_vcard: {
|
||||
id: 'cannot_parse_vcard',
|
||||
defaultMessage: 'Cannot parse vCard file.',
|
||||
description: 'Error message when vCard file cannot be parsed'
|
||||
}
|
||||
});
|
||||
|
||||
// Checks if the access permissions are granted but not yet accepted.
|
||||
@@ -144,6 +149,7 @@ class MessagesView extends React.Component {
|
||||
this.sendVideoAttachment = this.sendVideoAttachment.bind(this);
|
||||
this.sendFileAttachment = this.sendFileAttachment.bind(this);
|
||||
this.sendAudioAttachment = this.sendAudioAttachment.bind(this);
|
||||
this.sendTheCardAttachment = this.sendTheCardAttachment.bind(this);
|
||||
this.sendKeyPress = this.sendKeyPress.bind(this);
|
||||
this.subscribe = this.subscribe.bind(this);
|
||||
this.handleScrollReference = this.handleScrollReference.bind(this);
|
||||
@@ -1039,7 +1045,7 @@ class MessagesView extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
// Send attachment as Drafty message:
|
||||
// sendFileAttachment sends the file as Drafty message:
|
||||
// - if file is too large, upload it and send a s link.
|
||||
// - if file is small enough, just send it in-band.
|
||||
sendFileAttachment(file) {
|
||||
@@ -1047,6 +1053,15 @@ class MessagesView extends React.Component {
|
||||
const maxInbandAttachmentSize = (this.props.tinode.getServerParam('maxMessageSize',
|
||||
MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024) | 0;
|
||||
|
||||
if (TheCard.isFileSupported(file.type, file.name)) {
|
||||
// This is a vCard file, try to convert and send as TheCard.
|
||||
if (this.sendTheCardAttachment(file, maxInbandAttachmentSize)) {
|
||||
// Successfully sent as TheCard.
|
||||
return;
|
||||
}
|
||||
// Sending as TheCard failed, fall through to sending as generic file attachment.
|
||||
}
|
||||
|
||||
// If the attachment is a JSON file, then use 'application/octet-stream' instead of 'application/json'.
|
||||
// This is a temporary workaround for the collision with the 'application/json' MIME type of form responses.
|
||||
// Remove this code in 2026 or so.
|
||||
@@ -1081,6 +1096,26 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// Convert attached vCard to TheCard and send.
|
||||
sendTheCardAttachment(file, maxInbandAttachmentSize) {
|
||||
if (file.size > maxInbandAttachmentSize) {
|
||||
// Cannot convert to TheCard, send as a generic file attachment instead.
|
||||
return false;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const card = TheCard.importVCard(e.target.result);
|
||||
if (!card) {
|
||||
// Failed to parse vCard.
|
||||
this.props.onError(this.props.intl.formatMessage(messages.cannot_parse_vcard), 'err');
|
||||
}
|
||||
this.sendMessage(Drafty.appendTheCard(null, card));
|
||||
};
|
||||
reader.readAsText(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// handleAttachFile method is called when [Attach file] button is clicked: launch attachment preview.
|
||||
handleAttachFile(file) {
|
||||
const maxExternAttachmentSize = this.props.tinode.getServerParam('maxFileUploadSize', MAX_EXTERN_ATTACHMENT_SIZE);
|
||||
@@ -1777,7 +1812,7 @@ class MessagesView extends React.Component {
|
||||
null}
|
||||
<div className="avatar-box">
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
avatar={avatar}
|
||||
topic={this.state.topic}
|
||||
title={this.state.title}
|
||||
|
||||
@@ -48,7 +48,7 @@ export default class AvatarUpload extends React.Component {
|
||||
this.props.readOnly && this.props.uid ?
|
||||
<div className="avatar-box">
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
avatar={true}
|
||||
topic={this.props.uid}
|
||||
title={this.props.title} />
|
||||
|
||||
@@ -122,7 +122,7 @@ export default class CallIncoming extends React.Component {
|
||||
<div className="caller-card incoming pulse">
|
||||
<div className="avatar-box">
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
avatar={this.state.avatar || true}
|
||||
topic={this.props.topic}
|
||||
title={this.state.fullName} />
|
||||
|
||||
@@ -680,7 +680,7 @@ class CallPanel extends React.PureComponent {
|
||||
<div className={`caller-card${pulseAnimation} draggable`}>
|
||||
<div className="avatar-box">
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
avatar={this.props.avatar}
|
||||
topic={this.props.topic}
|
||||
title={this.props.title} />
|
||||
|
||||
@@ -26,22 +26,46 @@ class BaseChatMessage extends React.PureComponent {
|
||||
this.handleExpandImage = this.handleExpandImage.bind(this);
|
||||
this.handlePlayVideo = this.handlePlayVideo.bind(this);
|
||||
this.handleFormButtonClick = this.handleFormButtonClick.bind(this);
|
||||
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
||||
this.handleContextClick = this.handleContextClick.bind(this);
|
||||
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
||||
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
||||
this.handleDraftyClick = this.handleDraftyClick.bind(this);
|
||||
|
||||
this.formatterContext = {
|
||||
formatMessage: props.intl.formatMessage.bind(props.intl),
|
||||
viewportWidth: props.viewportWidth,
|
||||
authorizeURL: props.tinode.authorizeURL.bind(props.tinode),
|
||||
|
||||
onImagePreview: this.handleExpandImage,
|
||||
onVideoPreview: this.handlePlayVideo,
|
||||
onFormButtonClick: this.handleFormButtonClick,
|
||||
onQuoteClick: this.handleQuoteClick
|
||||
onHandleClick: this.handleDraftyClick
|
||||
};
|
||||
}
|
||||
|
||||
handleDraftyClick = (e, action) => {
|
||||
switch (action) {
|
||||
case 'image':
|
||||
this.handleExpandImage(e);
|
||||
break;
|
||||
case 'video':
|
||||
this.handlePlayVideo(e);
|
||||
break;
|
||||
case 'form_button':
|
||||
this.handleFormButtonClick(e);
|
||||
break;
|
||||
case 'quote':
|
||||
this.handleQuoteClick(e);
|
||||
break;
|
||||
case 'contact_chat':
|
||||
case 'contact_find':
|
||||
e.preventDefault();
|
||||
console.log('Contact click handling not implemented yet.', action, e.target.dataset);
|
||||
break;
|
||||
default:
|
||||
// No special handling; let the browser deal with it.
|
||||
console.log('Unhandled drafty action.', action, e.target.dataset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleExpandImage(e) {
|
||||
e.preventDefault();
|
||||
this.props.onExpandMedia({
|
||||
@@ -99,7 +123,7 @@ class BaseChatMessage extends React.PureComponent {
|
||||
if (!this.props.response) {
|
||||
let immutable = false;
|
||||
Drafty.entities(this.props.content, (_0, _1, tp) => {
|
||||
immutable = ['AU', 'EX', 'FM', 'IM', 'VC', 'VD'].includes(tp);
|
||||
immutable = ['AU', 'EX', 'FM', 'IM', 'TC', 'VC', 'VD'].includes(tp);
|
||||
return immutable;
|
||||
});
|
||||
if (!immutable) {
|
||||
@@ -200,7 +224,7 @@ class BaseChatMessage extends React.PureComponent {
|
||||
<div className="avatar-box">
|
||||
{fullDisplay ?
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
topic={this.props.userFrom}
|
||||
title={this.props.userName}
|
||||
avatar={avatar} /> :
|
||||
|
||||
@@ -23,7 +23,7 @@ export default class Chip extends React.PureComponent {
|
||||
<span className="spacer" /> :
|
||||
<div className="avatar-box">
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
avatar={this.props.avatar || true}
|
||||
topic={this.props.topic}
|
||||
title={this.props.title} />
|
||||
|
||||
@@ -122,7 +122,7 @@ class Contact extends React.Component {
|
||||
<li className={bgColor} onClick={this.handleClick}>
|
||||
<div className="avatar-box">
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
avatar={avatar}
|
||||
title={this.props.title}
|
||||
topic={this.props.item}
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class GroupSubs extends React.Component {
|
||||
usersOnline.push(
|
||||
<div className="avatar-box" key={sub.user}>
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
topic={sub.user}
|
||||
avatar={makeImageUrl(sub.public ? sub.public.photo : null) || true}
|
||||
title={sub.public ? sub.public.fn : null} />
|
||||
|
||||
@@ -27,7 +27,7 @@ export default class LetterTile extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
} else if (this.props.avatar) {
|
||||
const url = this.props.tinode.authorizeURL(sanitizeUrlForMime(this.props.avatar, 'image'));
|
||||
const url = this.props.authorizeURL(sanitizeUrlForMime(this.props.avatar, 'image'));
|
||||
// If avatar image is invalid, show a placeholder.
|
||||
const className = 'avatar' + (this.props.deleted ? ' deleted' : '');
|
||||
avatar = <img className={className} alt="avatar" src={url}
|
||||
|
||||
@@ -26,7 +26,7 @@ export default class SideNavbar extends React.PureComponent {
|
||||
{avatar ?
|
||||
<div id="self-avatar" className="avatar-box">
|
||||
<LetterTile
|
||||
tinode={this.props.tinode}
|
||||
authorizeURL={this.props.tinode.authorizeURL}
|
||||
avatar={avatar}
|
||||
topic={this.props.myUserId}
|
||||
title={this.props.title} />
|
||||
|
||||
Reference in New Issue
Block a user