added date badges (dividers) in messages view
This commit is contained in:
+19
-8
@@ -1557,12 +1557,6 @@ img.channel {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.chat-box .center {
|
||||
justify-content: center;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.bubble {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -1572,6 +1566,7 @@ img.channel {
|
||||
padding: 0.75rem 0.5rem 0.75rem 0.5rem;
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
color: #212121;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.12);
|
||||
transition: ease-out background-color 0.5s;
|
||||
@@ -1624,11 +1619,28 @@ img.channel {
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.center .bubble {
|
||||
.chat-box .meta {
|
||||
justify-content: center;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.chat-box .meta .bubble {
|
||||
color: #666;
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.meta .bubble.deleted {
|
||||
background-color: #e3f2fd;
|
||||
padding: 0.75rem 0.75rem 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
.meta .bubble.date {
|
||||
font-size: smaller;
|
||||
padding: 0.5rem 0.5rem 0.5rem 0.5rem;
|
||||
background-color: rgb(244 244 244 / 66%);
|
||||
}
|
||||
|
||||
/* Left triangle placed bottom left flush. */
|
||||
.left .bubble.tip::before {
|
||||
content: '';
|
||||
@@ -1691,7 +1703,6 @@ img.channel {
|
||||
|
||||
.bubble div.message-content {
|
||||
position: relative;
|
||||
color: #212121;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
max-width: 36rem;
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -70,7 +70,7 @@
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-intl": "^5.20.2",
|
||||
"tinode-sdk": "^0.18.0-rc3"
|
||||
"tinode-sdk": "^0.18.1-beta1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.5",
|
||||
|
||||
+53
-31
@@ -14,6 +14,7 @@ import Invitation from '../widgets/invitation.jsx';
|
||||
import LetterTile from '../widgets/letter-tile.jsx';
|
||||
import LoadSpinner from '../widgets/load-spinner.jsx';
|
||||
import LogoView from './logo-view.jsx';
|
||||
import MetaMessage from '../widgets/meta-message.jsx';
|
||||
import SendMessage from '../widgets/send-message.jsx';
|
||||
|
||||
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY,
|
||||
@@ -971,9 +972,11 @@ class MessagesView extends React.Component {
|
||||
icon_badges.push({icon: 'dangerous', color: 'badge-inv'});
|
||||
}
|
||||
}
|
||||
let messageNodes = [];
|
||||
|
||||
const messageNodes = [];
|
||||
let previousFrom = null;
|
||||
let chatBoxClass = null;
|
||||
const dateFmt = new Intl.DateTimeFormat(this.props.intl.locale);
|
||||
topic.messages((msg, prev, next, i) => {
|
||||
let nextFrom = next ? (next.from || 'chan') : null;
|
||||
|
||||
@@ -1008,36 +1011,55 @@ class MessagesView extends React.Component {
|
||||
replyToSeq = null;
|
||||
}
|
||||
|
||||
messageNodes.push(
|
||||
<ChatMessage
|
||||
tinode={this.props.tinode}
|
||||
content={msg.content}
|
||||
deleted={msg.hi}
|
||||
mimeType={msg.head ? msg.head.mime : null}
|
||||
timestamp={msg.ts}
|
||||
response={isReply}
|
||||
seq={msg.seq}
|
||||
isGroup={groupTopic}
|
||||
isChan={this.state.channel}
|
||||
userFrom={userFrom}
|
||||
userName={userName}
|
||||
userAvatar={userAvatar}
|
||||
sequence={sequence}
|
||||
received={deliveryStatus}
|
||||
uploader={msg._uploader}
|
||||
viewportWidth={this.props.viewportWidth} // Used by `formatter`.
|
||||
showContextMenu={this.handleShowMessageContextMenu}
|
||||
onImagePreview={this.handleImagePostview}
|
||||
onFormResponse={this.handleFormResponse}
|
||||
onError={this.props.onError}
|
||||
onCancelUpload={this.handleCancelUpload}
|
||||
pickReply={this.handlePickReply}
|
||||
replyToSeq={replyToSeq}
|
||||
onQuoteClick={this.handleQuoteClick}
|
||||
ref={ref}
|
||||
userIsWriter={this.state.isWriter}
|
||||
key={msg.seq} />
|
||||
);
|
||||
// This message was sent on a different date than the previous.
|
||||
if (!prev || new Date(prev.ts).toDateString() != new Date(msg.ts).toDateString()) {
|
||||
messageNodes.push(
|
||||
<MetaMessage
|
||||
date={dateFmt.format(msg.ts)}
|
||||
locale={this.props.intl.locale}
|
||||
key={'date-' + msg.seq} />
|
||||
);
|
||||
}
|
||||
|
||||
if (msg.hi) {
|
||||
// Deleted message.
|
||||
messageNodes.push(
|
||||
<MetaMessage
|
||||
deleted={true}
|
||||
key={msg.seq} />
|
||||
);
|
||||
} else {
|
||||
messageNodes.push(
|
||||
<ChatMessage
|
||||
tinode={this.props.tinode}
|
||||
content={msg.content}
|
||||
deleted={msg.hi}
|
||||
mimeType={msg.head ? msg.head.mime : null}
|
||||
timestamp={msg.ts}
|
||||
response={isReply}
|
||||
seq={msg.seq}
|
||||
isGroup={groupTopic}
|
||||
isChan={this.state.channel}
|
||||
userFrom={userFrom}
|
||||
userName={userName}
|
||||
userAvatar={userAvatar}
|
||||
sequence={sequence}
|
||||
received={deliveryStatus}
|
||||
uploader={msg._uploader}
|
||||
viewportWidth={this.props.viewportWidth} // Used by `formatter`.
|
||||
showContextMenu={this.handleShowMessageContextMenu}
|
||||
onImagePreview={this.handleImagePostview}
|
||||
onFormResponse={this.handleFormResponse}
|
||||
onError={this.props.onError}
|
||||
onCancelUpload={this.handleCancelUpload}
|
||||
pickReply={this.handlePickReply}
|
||||
replyToSeq={replyToSeq}
|
||||
onQuoteClick={this.handleQuoteClick}
|
||||
ref={ref}
|
||||
userIsWriter={this.state.isWriter}
|
||||
key={msg.seq} />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let lastSeen = null;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Single message, sent or received.
|
||||
// Single chat message bubble, sent or received.
|
||||
|
||||
import React from 'react';
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import { Drafty } from 'tinode-sdk';
|
||||
@@ -110,11 +111,10 @@ class BaseChatMessage extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const sideClass = this.props.deleted ? 'center' :
|
||||
(this.props.sequence + ' ' + (this.props.response ? 'left' : 'right'));
|
||||
const sideClass = this.props.sequence + ' ' + (this.props.response ? 'left' : 'right');
|
||||
const bubbleClass = (this.props.sequence == 'single' || this.props.sequence == 'last') ? 'bubble tip' : 'bubble';
|
||||
const avatar = this.props.deleted ? null : (this.props.userAvatar || true);
|
||||
const fullDisplay = (this.props.isGroup && this.props.response && !this.props.deleted &&
|
||||
const avatar = this.props.userAvatar || true;
|
||||
const fullDisplay = (this.props.isGroup && this.props.response &&
|
||||
(this.props.sequence == 'single' || this.props.sequence == 'last'));
|
||||
|
||||
let content = this.props.content;
|
||||
@@ -140,12 +140,6 @@ class BaseChatMessage extends React.PureComponent {
|
||||
}, this);
|
||||
const tree = Drafty.format(content, fullFormatter, this.formatterContext);
|
||||
content = React.createElement(React.Fragment, null, tree);
|
||||
} else if (this.props.deleted) {
|
||||
// Message represents a range of deleted messages.
|
||||
content = <><i className="material-icons gray">block</i> <i className="gray">
|
||||
<FormattedMessage id="deleted_content"
|
||||
defaultMessage="content deleted" description="Shown when messages are deleted" />
|
||||
</i></>
|
||||
} else if (typeof content != 'string') {
|
||||
content = <><i className="material-icons gray">warning_amber</i> <i className="gray">
|
||||
<FormattedMessage id="invalid_content"
|
||||
@@ -178,13 +172,12 @@ class BaseChatMessage extends React.PureComponent {
|
||||
received={this.props.received} />
|
||||
: null}
|
||||
</div>
|
||||
{this.props.deleted || !this.props.showContextMenu ?
|
||||
null :
|
||||
{this.props.showContextMenu ?
|
||||
<span className="menuTrigger">
|
||||
<a href="#" onClick={this.handleContextClick}>
|
||||
<i className="material-icons">expand_more</i>
|
||||
</a>
|
||||
</span>
|
||||
</span> : null
|
||||
}
|
||||
</div>
|
||||
{fullDisplay ?
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Message bubble with non-payload content, such as an indicator of deleted content or a date stamp.
|
||||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export default class MetaMessage extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let content = null;
|
||||
let bubbleClass = 'bubble';
|
||||
if (this.props.deleted) {
|
||||
// Message represents a range of deleted messages.
|
||||
content = <><i className="material-icons gray">block</i> <i className="gray">
|
||||
<FormattedMessage id="deleted_content"
|
||||
defaultMessage="content deleted" description="Shown when messages are deleted" />
|
||||
</i></>
|
||||
bubbleClass += ' deleted';
|
||||
} else if (this.props.date) {
|
||||
// A date badge.
|
||||
content = <>{this.props.date}</>
|
||||
bubbleClass += ' date';
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
return <>{null}</>
|
||||
}
|
||||
|
||||
return (
|
||||
<li className="meta">
|
||||
<div className={bubbleClass}>
|
||||
<div className="message-content">
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -4,7 +4,6 @@ import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import Tinode from 'tinode-sdk';
|
||||
|
||||
import { shortDateFormat } from '../lib/strformat.js';
|
||||
import { deliveryMarker } from '../lib/utils.js';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -29,7 +28,7 @@ class ReceivedMarker extends React.PureComponent {
|
||||
} else if (this.props.received == Tinode.MESSAGE_STATUS_FAILED) {
|
||||
timestamp = formatMessage(messages.message_sending_failed);
|
||||
} else {
|
||||
timestamp = shortDateFormat(this.props.timestamp, this.props.intl.locale);
|
||||
timestamp = this.props.timestamp.toLocaleTimeString(this.props.intl.locale, { timeStyle: 'short' });
|
||||
}
|
||||
|
||||
const icon = deliveryMarker(this.props.received);
|
||||
|
||||
+146
-79
@@ -3296,11 +3296,12 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../widgets/letter-tile.jsx */ "./src/widgets/letter-tile.jsx");
|
||||
/* harmony import */ var _widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../widgets/load-spinner.jsx */ "./src/widgets/load-spinner.jsx");
|
||||
/* harmony import */ var _logo_view_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./logo-view.jsx */ "./src/views/logo-view.jsx");
|
||||
/* harmony import */ var _widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../widgets/send-message.jsx */ "./src/widgets/send-message.jsx");
|
||||
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
|
||||
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
|
||||
/* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js");
|
||||
/* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js");
|
||||
/* harmony import */ var _widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../widgets/meta-message.jsx */ "./src/widgets/meta-message.jsx");
|
||||
/* harmony import */ var _widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../widgets/send-message.jsx */ "./src/widgets/send-message.jsx");
|
||||
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
|
||||
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
|
||||
/* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js");
|
||||
/* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js");
|
||||
|
||||
|
||||
|
||||
@@ -3320,6 +3321,7 @@ const Drafty = (tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default().Drafty);
|
||||
|
||||
|
||||
|
||||
|
||||
const NOTIFICATION_EXEC_INTERVAL = 300;
|
||||
const SHOW_GO_TO_LAST_DIST = 100;
|
||||
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
||||
@@ -3563,7 +3565,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
if (topic.public) {
|
||||
Object.assign(nextState, {
|
||||
title: topic.public.fn,
|
||||
avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.makeImageUrl)(topic.public.photo)
|
||||
avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.makeImageUrl)(topic.public.photo)
|
||||
});
|
||||
} else {
|
||||
Object.assign(nextState, {
|
||||
@@ -3656,7 +3658,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub();
|
||||
|
||||
if (this.state.isReader || newTopic) {
|
||||
getQuery = getQuery.withLaterData(_config_js__WEBPACK_IMPORTED_MODULE_14__.MESSAGES_PAGE);
|
||||
getQuery = getQuery.withLaterData(_config_js__WEBPACK_IMPORTED_MODULE_15__.MESSAGES_PAGE);
|
||||
|
||||
if (this.state.isReader) {
|
||||
getQuery = getQuery.withLaterDel();
|
||||
@@ -3670,7 +3672,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
const setQuery = newTopic ? this.props.newTopicParams : undefined;
|
||||
topic.subscribe(getQuery.build(), setQuery).then(ctrl => {
|
||||
if (ctrl.code == 303) {
|
||||
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_16__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_16__["default"].setUrlTopic('', ctrl.params.topic));
|
||||
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_17__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_17__["default"].setUrlTopic('', ctrl.params.topic));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3743,7 +3745,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
this.setState({
|
||||
fetchingMessages: true
|
||||
}, () => {
|
||||
topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_14__.MESSAGES_PAGE).catch(err => this.props.onError(err.message, 'err')).finally(() => this.setState({
|
||||
topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_15__.MESSAGES_PAGE).catch(err => this.props.onError(err.message, 'err')).finally(() => this.setState({
|
||||
fetchingMessages: false
|
||||
}));
|
||||
});
|
||||
@@ -3765,7 +3767,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
if (desc.public) {
|
||||
this.setState({
|
||||
title: desc.public.fn,
|
||||
avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.makeImageUrl)(desc.public.photo)
|
||||
avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.makeImageUrl)(desc.public.photo)
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
@@ -3831,7 +3833,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
this.readNotificationQueue.push({
|
||||
topicName: this.state.topic,
|
||||
seq: seq,
|
||||
sendAt: now.setMilliseconds(now.getMilliseconds() + _config_js__WEBPACK_IMPORTED_MODULE_14__.READ_DELAY)
|
||||
sendAt: now.setMilliseconds(now.getMilliseconds() + _config_js__WEBPACK_IMPORTED_MODULE_15__.READ_DELAY)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3928,7 +3930,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
this.setState({
|
||||
typingIndicator: false
|
||||
});
|
||||
}, _config_js__WEBPACK_IMPORTED_MODULE_14__.KEYPRESS_DELAY + 1000);
|
||||
}, _config_js__WEBPACK_IMPORTED_MODULE_15__.KEYPRESS_DELAY + 1000);
|
||||
|
||||
if (!this.state.typingIndicator) {
|
||||
this.setState({
|
||||
@@ -4035,7 +4037,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
|
||||
handleEnablePeer(e) {
|
||||
e.preventDefault();
|
||||
this.props.onChangePermissions(this.state.topic, _config_js__WEBPACK_IMPORTED_MODULE_14__.DEFAULT_P2P_ACCESS_MODE, this.state.topic);
|
||||
this.props.onChangePermissions(this.state.topic, _config_js__WEBPACK_IMPORTED_MODULE_15__.DEFAULT_P2P_ACCESS_MODE, this.state.topic);
|
||||
}
|
||||
|
||||
sendKeyPress() {
|
||||
@@ -4074,7 +4076,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
|
||||
sendFileAttachment(file) {
|
||||
const maxInbandAttachmentSize = this.props.tinode.getServerLimit('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_14__.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;
|
||||
|
||||
if (file.size > maxInbandAttachmentSize) {
|
||||
const uploader = this.props.tinode.getLargeFileHelper();
|
||||
@@ -4087,7 +4089,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
});
|
||||
this.sendMessage(msg, uploadCompletionPromise, uploader);
|
||||
} else {
|
||||
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.fileToBase64)(file).then(b64 => this.sendMessage(Drafty.attachFile(null, {
|
||||
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.fileToBase64)(file).then(b64 => this.sendMessage(Drafty.attachFile(null, {
|
||||
mime: b64.mime,
|
||||
data: b64.bits,
|
||||
filename: b64.name
|
||||
@@ -4096,12 +4098,12 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
|
||||
handleAttachFile(file) {
|
||||
const maxExternAttachmentSize = this.props.tinode.getServerLimit('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_14__.MAX_EXTERN_ATTACHMENT_SIZE);
|
||||
const maxExternAttachmentSize = this.props.tinode.getServerLimit('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_EXTERN_ATTACHMENT_SIZE);
|
||||
|
||||
if (file.size > maxExternAttachmentSize) {
|
||||
this.props.onError(this.props.intl.formatMessage(messages.file_attachment_too_large, {
|
||||
size: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_17__.bytesToHumanSize)(file.size),
|
||||
limit: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_17__.bytesToHumanSize)(maxExternAttachmentSize)
|
||||
size: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_18__.bytesToHumanSize)(file.size),
|
||||
limit: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_18__.bytesToHumanSize)(maxExternAttachmentSize)
|
||||
}), 'err');
|
||||
} else {
|
||||
this.setState({
|
||||
@@ -4120,7 +4122,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
const width = this.state.imagePreview.width;
|
||||
const height = this.state.imagePreview.height;
|
||||
const fname = this.state.imagePreview.name;
|
||||
const maxInbandAttachmentSize = this.props.tinode.getServerLimit('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_14__.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;
|
||||
|
||||
if (blob.size > maxInbandAttachmentSize) {
|
||||
const uploader = this.props.tinode.getLargeFileHelper();
|
||||
@@ -4131,7 +4133,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
|
||||
const uploadCompletionPromise = uploader.upload(blob);
|
||||
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_14__.IMAGE_PREVIEW_DIM, _config_js__WEBPACK_IMPORTED_MODULE_14__.IMAGE_PREVIEW_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.blobToBase64)(scaled.blob)).then(b64 => {
|
||||
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_15__.IMAGE_PREVIEW_DIM, _config_js__WEBPACK_IMPORTED_MODULE_15__.IMAGE_PREVIEW_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.blobToBase64)(scaled.blob)).then(b64 => {
|
||||
let msg = Drafty.insertImage(null, 0, {
|
||||
mime: mime,
|
||||
_tempPreview: b64.bits,
|
||||
@@ -4154,7 +4156,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
return;
|
||||
}
|
||||
|
||||
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.blobToBase64)(blob).then(b64 => {
|
||||
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.blobToBase64)(blob).then(b64 => {
|
||||
let msg = Drafty.insertImage(null, 0, {
|
||||
mime: b64.mime,
|
||||
preview: b64.bits,
|
||||
@@ -4174,8 +4176,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
|
||||
handleAttachImage(file) {
|
||||
const maxExternAttachmentSize = this.props.tinode.getServerLimit('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_14__.MAX_EXTERN_ATTACHMENT_SIZE);
|
||||
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.imageScaled)(file, _config_js__WEBPACK_IMPORTED_MODULE_14__.MAX_IMAGE_DIM, _config_js__WEBPACK_IMPORTED_MODULE_14__.MAX_IMAGE_DIM, maxExternAttachmentSize, false).then(scaled => {
|
||||
const maxExternAttachmentSize = this.props.tinode.getServerLimit('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_EXTERN_ATTACHMENT_SIZE);
|
||||
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.imageScaled)(file, _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_IMAGE_DIM, _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_IMAGE_DIM, maxExternAttachmentSize, false).then(scaled => {
|
||||
this.setState({
|
||||
imagePreview: {
|
||||
url: URL.createObjectURL(scaled.blob),
|
||||
@@ -4215,7 +4217,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
content = typeof content == 'string' ? Drafty.init(content) : content;
|
||||
|
||||
if (Drafty.isValid(content)) {
|
||||
content = Drafty.replyContent(content, _config_js__WEBPACK_IMPORTED_MODULE_14__.QUOTED_REPLY_LENGTH);
|
||||
content = Drafty.replyContent(content, _config_js__WEBPACK_IMPORTED_MODULE_15__.QUOTED_REPLY_LENGTH);
|
||||
} else {
|
||||
content = Drafty.append(Drafty.init('\u26A0 '), Drafty.wrapInto(this.props.intl.formatMessage(messages.invalid_content), 'EM'));
|
||||
}
|
||||
@@ -4321,9 +4323,10 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
}
|
||||
|
||||
let messageNodes = [];
|
||||
const messageNodes = [];
|
||||
let previousFrom = null;
|
||||
let chatBoxClass = null;
|
||||
const dateFmt = new Intl.DateTimeFormat(this.props.intl.locale);
|
||||
topic.messages((msg, prev, next, i) => {
|
||||
let nextFrom = next ? next.from || 'chan' : null;
|
||||
let sequence = 'single';
|
||||
@@ -4349,7 +4352,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
|
||||
if (user && user.public) {
|
||||
userName = user.public.fn;
|
||||
userAvatar = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.makeImageUrl)(user.public.photo);
|
||||
userAvatar = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.makeImageUrl)(user.public.photo);
|
||||
}
|
||||
|
||||
chatBoxClass = groupTopic ? 'chat-box group' : 'chat-box';
|
||||
@@ -4360,35 +4363,50 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
replyToSeq = null;
|
||||
}
|
||||
|
||||
messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_chat_message_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], {
|
||||
tinode: this.props.tinode,
|
||||
content: msg.content,
|
||||
deleted: msg.hi,
|
||||
mimeType: msg.head ? msg.head.mime : null,
|
||||
timestamp: msg.ts,
|
||||
response: isReply,
|
||||
seq: msg.seq,
|
||||
isGroup: groupTopic,
|
||||
isChan: this.state.channel,
|
||||
userFrom: userFrom,
|
||||
userName: userName,
|
||||
userAvatar: userAvatar,
|
||||
sequence: sequence,
|
||||
received: deliveryStatus,
|
||||
uploader: msg._uploader,
|
||||
viewportWidth: this.props.viewportWidth,
|
||||
showContextMenu: this.handleShowMessageContextMenu,
|
||||
onImagePreview: this.handleImagePostview,
|
||||
onFormResponse: this.handleFormResponse,
|
||||
onError: this.props.onError,
|
||||
onCancelUpload: this.handleCancelUpload,
|
||||
pickReply: this.handlePickReply,
|
||||
replyToSeq: replyToSeq,
|
||||
onQuoteClick: this.handleQuoteClick,
|
||||
ref: ref,
|
||||
userIsWriter: this.state.isWriter,
|
||||
key: msg.seq
|
||||
}));
|
||||
if (!prev || new Date(prev.ts).toDateString() != new Date(msg.ts).toDateString()) {
|
||||
messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_13__["default"], {
|
||||
date: dateFmt.format(msg.ts),
|
||||
locale: this.props.intl.locale,
|
||||
key: 'date-' + msg.seq
|
||||
}));
|
||||
}
|
||||
|
||||
if (msg.hi) {
|
||||
messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_13__["default"], {
|
||||
deleted: true,
|
||||
key: msg.seq
|
||||
}));
|
||||
} else {
|
||||
messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_chat_message_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], {
|
||||
tinode: this.props.tinode,
|
||||
content: msg.content,
|
||||
deleted: msg.hi,
|
||||
mimeType: msg.head ? msg.head.mime : null,
|
||||
timestamp: msg.ts,
|
||||
response: isReply,
|
||||
seq: msg.seq,
|
||||
isGroup: groupTopic,
|
||||
isChan: this.state.channel,
|
||||
userFrom: userFrom,
|
||||
userName: userName,
|
||||
userAvatar: userAvatar,
|
||||
sequence: sequence,
|
||||
received: deliveryStatus,
|
||||
uploader: msg._uploader,
|
||||
viewportWidth: this.props.viewportWidth,
|
||||
showContextMenu: this.handleShowMessageContextMenu,
|
||||
onImagePreview: this.handleImagePostview,
|
||||
onFormResponse: this.handleFormResponse,
|
||||
onError: this.props.onError,
|
||||
onCancelUpload: this.handleCancelUpload,
|
||||
pickReply: this.handlePickReply,
|
||||
replyToSeq: replyToSeq,
|
||||
onQuoteClick: this.handleQuoteClick,
|
||||
ref: ref,
|
||||
userIsWriter: this.state.isWriter,
|
||||
key: msg.seq
|
||||
}));
|
||||
}
|
||||
});
|
||||
let lastSeen = null;
|
||||
|
||||
@@ -4401,7 +4419,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
if (cont.online) {
|
||||
lastSeen = formatMessage(messages.online_now);
|
||||
} else if (cont.seen) {
|
||||
lastSeen = formatMessage(messages.last_seen) + ": " + (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_17__.shortDateFormat)(cont.seen.when, this.props.intl.locale);
|
||||
lastSeen = formatMessage(messages.last_seen) + ": " + (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_18__.shortDateFormat)(cont.seen.when, this.props.intl.locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4504,7 +4522,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}]
|
||||
})), ".") : null, this.state.unconfirmed ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_invitation_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], {
|
||||
onAction: this.handleNewChatAcceptance
|
||||
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_13__["default"], {
|
||||
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_14__["default"], {
|
||||
tinode: this.props.tinode,
|
||||
noInput: !!this.props.forwardMessage,
|
||||
disabled: !this.state.isWriter,
|
||||
@@ -7952,10 +7970,10 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
}
|
||||
|
||||
render() {
|
||||
const sideClass = this.props.deleted ? 'center' : this.props.sequence + ' ' + (this.props.response ? 'left' : 'right');
|
||||
const sideClass = this.props.sequence + ' ' + (this.props.response ? 'left' : 'right');
|
||||
const bubbleClass = this.props.sequence == 'single' || this.props.sequence == 'last' ? 'bubble tip' : 'bubble';
|
||||
const avatar = this.props.deleted ? null : this.props.userAvatar || true;
|
||||
const fullDisplay = this.props.isGroup && this.props.response && !this.props.deleted && (this.props.sequence == 'single' || this.props.sequence == 'last');
|
||||
const avatar = this.props.userAvatar || true;
|
||||
const fullDisplay = this.props.isGroup && this.props.response && (this.props.sequence == 'single' || this.props.sequence == 'last');
|
||||
let content = this.props.content;
|
||||
const attachments = [];
|
||||
|
||||
@@ -7980,18 +7998,6 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
}, 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);
|
||||
} 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", {
|
||||
className: "material-icons gray"
|
||||
}, "block"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "gray"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
||||
id: "deleted_content",
|
||||
defaultMessage: [{
|
||||
"type": 0,
|
||||
"value": "content deleted"
|
||||
}]
|
||||
})));
|
||||
} else if (typeof content != 'string') {
|
||||
content = 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"
|
||||
@@ -8025,14 +8031,14 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
}, content, attachments), this.props.timestamp ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_received_marker_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], {
|
||||
timestamp: this.props.timestamp,
|
||||
received: this.props.received
|
||||
}) : null), this.props.deleted || !this.props.showContextMenu ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
|
||||
}) : null), this.props.showContextMenu ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
|
||||
className: "menuTrigger"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
href: "#",
|
||||
onClick: this.handleContextClick
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "material-icons"
|
||||
}, "expand_more")))), fullDisplay ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
}, "expand_more"))) : null), fullDisplay ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "author"
|
||||
}, this.props.userName || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
||||
id: "user_not_found",
|
||||
@@ -10941,6 +10947,67 @@ class MenuStart extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCompon
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./src/widgets/meta-message.jsx":
|
||||
/*!**************************************!*\
|
||||
!*** ./src/widgets/meta-message.jsx ***!
|
||||
\**************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "default": () => (/* binding */ MetaMessage)
|
||||
/* 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__);
|
||||
|
||||
|
||||
class MetaMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let content = null;
|
||||
let bubbleClass = 'bubble';
|
||||
|
||||
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", {
|
||||
className: "material-icons gray"
|
||||
}, "block"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "gray"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
||||
id: "deleted_content",
|
||||
defaultMessage: [{
|
||||
"type": 0,
|
||||
"value": "content deleted"
|
||||
}]
|
||||
})));
|
||||
bubbleClass += ' deleted';
|
||||
} else if (this.props.date) {
|
||||
content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, this.props.date);
|
||||
bubbleClass += ' date';
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, null);
|
||||
}
|
||||
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", {
|
||||
className: "meta"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: bubbleClass
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "message-content"
|
||||
}, content)));
|
||||
}
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./src/widgets/new-topic-by-id.jsx":
|
||||
/*!*****************************************!*\
|
||||
!*** ./src/widgets/new-topic-by-id.jsx ***!
|
||||
@@ -11559,9 +11626,7 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
|
||||
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
|
||||
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
|
||||
/* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js");
|
||||
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
||||
|
||||
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
||||
|
||||
|
||||
|
||||
@@ -11595,10 +11660,12 @@ class ReceivedMarker extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
||||
} else if (this.props.received == (tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default().MESSAGE_STATUS_FAILED)) {
|
||||
timestamp = formatMessage(messages.message_sending_failed);
|
||||
} else {
|
||||
timestamp = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.shortDateFormat)(this.props.timestamp, this.props.intl.locale);
|
||||
timestamp = this.props.timestamp.toLocaleTimeString(this.props.intl.locale, {
|
||||
timeStyle: 'short'
|
||||
});
|
||||
}
|
||||
|
||||
const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.deliveryMarker)(this.props.received);
|
||||
const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.deliveryMarker)(this.props.received);
|
||||
const marker = icon ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: 'material-icons small ' + icon.color
|
||||
}, icon.name) : null;
|
||||
|
||||
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
Reference in New Issue
Block a user