video works although may have bugs

This commit is contained in:
or-else
2022-12-14 16:50:00 -08:00
parent 830d15f7ec
commit 8c3287941a
10 changed files with 229 additions and 67 deletions
+1
View File
@@ -189,6 +189,7 @@ function handleImageData(el, data, attr) {
}; };
if (!Drafty.isProcessing(data)) { if (!Drafty.isProcessing(data)) {
attr.src = this.authorizeURL(sanitizeUrlForMime(attr.src, 'image')); attr.src = this.authorizeURL(sanitizeUrlForMime(attr.src, 'image'));
attr['data-src'] = sanitizeUrlForMime(attr.src, 'video');
attr.alt = data.name; attr.alt = data.name;
if (attr.src) { if (attr.src) {
if (Math.max(data.width || 0, data.height || 0) > IMAGE_THUMBNAIL_DIM) { if (Math.max(data.width || 0, data.height || 0) > IMAGE_THUMBNAIL_DIM) {
+32 -10
View File
@@ -123,7 +123,7 @@ class MessagesView extends React.Component {
this.handleMessageUpdate = this.handleMessageUpdate.bind(this); this.handleMessageUpdate = this.handleMessageUpdate.bind(this);
this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this); this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this);
this.handleInfoReceipt = this.handleInfoReceipt.bind(this); this.handleInfoReceipt = this.handleInfoReceipt.bind(this);
this.handleImagePostview = this.handleImagePostview.bind(this); this.handleExpandMedia = this.handleExpandMedia.bind(this);
this.handleClosePreview = this.handleClosePreview.bind(this); this.handleClosePreview = this.handleClosePreview.bind(this);
this.handleFormResponse = this.handleFormResponse.bind(this); this.handleFormResponse = this.handleFormResponse.bind(this);
this.handleContextClick = this.handleContextClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this);
@@ -274,6 +274,8 @@ class MessagesView extends React.Component {
docPreview: null, docPreview: null,
imagePreview: null, imagePreview: null,
imagePostview: null, imagePostview: null,
videoPreview: null,
videoPostview: null,
rtcPanel: null, rtcPanel: null,
typingIndicator: false, typingIndicator: false,
scrollPosition: 0, scrollPosition: 0,
@@ -282,7 +284,8 @@ class MessagesView extends React.Component {
channel: false, channel: false,
reply: null, reply: null,
contentToEdit: null, contentToEdit: null,
showGoToLastButton: false showGoToLastButton: false,
dragging: false
}; };
} else if (nextProps.topic != prevState.topic) { } else if (nextProps.topic != prevState.topic) {
const topic = nextProps.tinode.getTopic(nextProps.topic); const topic = nextProps.tinode.getTopic(nextProps.topic);
@@ -292,12 +295,15 @@ class MessagesView extends React.Component {
docPreview: null, docPreview: null,
imagePreview: null, imagePreview: null,
imagePostview: null, imagePostview: null,
videoPreview: null,
videoPostview: null,
rtcPanel: null, rtcPanel: null,
typingIndicator: false, typingIndicator: false,
scrollPosition: 0, scrollPosition: 0,
fetchingMessages: false, fetchingMessages: false,
showGoToLastButton: false, showGoToLastButton: false,
deleted: topic._deleted deleted: topic._deleted,
dragging: false
}; };
if (nextProps.forwardMessage) { if (nextProps.forwardMessage) {
@@ -721,8 +727,16 @@ class MessagesView extends React.Component {
} }
} }
handleImagePostview(content) { handleExpandMedia(content) {
this.setState({ imagePostview: content }); if (!content) {
return;
}
if (content.video) {
this.setState({ videoPostview: content });
} else {
this.setState({ imagePostview: content });
}
} }
handleClosePreview() { handleClosePreview() {
@@ -732,7 +746,7 @@ class MessagesView extends React.Component {
if (this.state.videoPreview && this.state.videoPreview.url) { if (this.state.videoPreview && this.state.videoPreview.url) {
URL.revokeObjectURL(this.state.videoPreview.url); URL.revokeObjectURL(this.state.videoPreview.url);
} }
this.setState({ imagePostview: null, imagePreview: null, docPreview: null, videoPreview: null }); this.setState({ imagePostview: null, imagePreview: null, docPreview: null, videoPreview: null, videoPostview: null});
} }
handleFormResponse(action, text, data) { handleFormResponse(action, text, data) {
@@ -912,7 +926,7 @@ class MessagesView extends React.Component {
const mime = this.state.imagePreview.mime; const mime = this.state.imagePreview.mime;
const width = this.state.imagePreview.width; const width = this.state.imagePreview.width;
const height = this.state.imagePreview.height; const height = this.state.imagePreview.height;
const fname = this.state.imagePreview.name; const fname = this.state.imagePreview.filename;
// Server-provided limit reduced for base64 encoding and overhead. // Server-provided limit reduced for base64 encoding and overhead.
const maxInbandAttachmentSize = (this.props.tinode.getServerParam('maxMessageSize', const maxInbandAttachmentSize = (this.props.tinode.getServerParam('maxMessageSize',
@@ -1067,7 +1081,7 @@ class MessagesView extends React.Component {
this.setState({videoPreview: { this.setState({videoPreview: {
url: URL.createObjectURL(file), url: URL.createObjectURL(file),
blob: file, blob: file,
name: file.name, filename: file.name,
size: file.size, size: file.size,
mime: file.type mime: file.type
}}); }});
@@ -1080,7 +1094,7 @@ class MessagesView extends React.Component {
this.setState({imagePreview: { this.setState({imagePreview: {
url: URL.createObjectURL(scaled.blob), url: URL.createObjectURL(scaled.blob),
blob: scaled.blob, blob: scaled.blob,
name: scaled.name, filename: scaled.name,
width: scaled.width, width: scaled.width,
height: scaled.height, height: scaled.height,
size: scaled.blob.size, size: scaled.blob.size,
@@ -1309,6 +1323,14 @@ class MessagesView extends React.Component {
content={this.state.imagePostview} content={this.state.imagePostview}
onClose={this.handleClosePreview} /> onClose={this.handleClosePreview} />
); );
} else if (this.state.videoPostview) {
// Play received video.
component2 = (
<VideoPreview
content={this.state.videoPostview}
tinode={this.props.tinode}
onClose={this.handleClosePreview} />
);
} else if (this.state.docPreview) { } else if (this.state.docPreview) {
// Preview attachment before sending. // Preview attachment before sending.
component2 = ( component2 = (
@@ -1432,7 +1454,7 @@ class MessagesView extends React.Component {
userIsWriter={this.state.isWriter} userIsWriter={this.state.isWriter}
viewportWidth={this.props.viewportWidth} // Used by `formatter`. viewportWidth={this.props.viewportWidth} // Used by `formatter`.
showContextMenu={this.handleShowMessageContextMenu} showContextMenu={this.handleShowMessageContextMenu}
onImagePreview={this.handleImagePostview} onExpandMedia={this.handleExpandMedia}
onFormResponse={this.handleFormResponse} onFormResponse={this.handleFormResponse}
onCancelUpload={this.handleCancelUpload} onCancelUpload={this.handleCancelUpload}
pickReply={this.handlePickReply} pickReply={this.handlePickReply}
+22 -6
View File
@@ -23,7 +23,8 @@ class BaseChatMessage extends React.PureComponent {
props.uploader.onProgress = this.handleProgress.bind(this); props.uploader.onProgress = this.handleProgress.bind(this);
} }
this.handleImagePreview = this.handleImagePreview.bind(this); this.handleExpandImage = this.handleExpandImage.bind(this);
this.handlePlayVideo = this.handlePlayVideo.bind(this);
this.handleFormButtonClick = this.handleFormButtonClick.bind(this); this.handleFormButtonClick = this.handleFormButtonClick.bind(this);
this.handleContextClick = this.handleContextClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this);
this.handleCancelUpload = this.handleCancelUpload.bind(this); this.handleCancelUpload = this.handleCancelUpload.bind(this);
@@ -34,18 +35,18 @@ class BaseChatMessage extends React.PureComponent {
viewportWidth: props.viewportWidth, viewportWidth: props.viewportWidth,
authorizeURL: props.tinode.authorizeURL.bind(props.tinode), authorizeURL: props.tinode.authorizeURL.bind(props.tinode),
onImagePreview: this.handleImagePreview, onImagePreview: this.handleExpandImage,
onVideoPreview: this.handleImagePreview, onVideoPreview: this.handlePlayVideo,
onFormButtonClick: this.handleFormButtonClick, onFormButtonClick: this.handleFormButtonClick,
onQuoteClick: this.handleQuoteClick onQuoteClick: this.handleQuoteClick
}; };
} }
handleImagePreview(e) { handleExpandImage(e) {
e.preventDefault(); e.preventDefault();
this.props.onImagePreview({ this.props.onExpandMedia({
url: e.target.src, url: e.target.src,
filename: e.target.title, filename: e.target.dataset.name,
width: e.target.dataset.width, width: e.target.dataset.width,
height: e.target.dataset.height, height: e.target.dataset.height,
size: e.target.dataset.size, size: e.target.dataset.size,
@@ -53,6 +54,21 @@ class BaseChatMessage extends React.PureComponent {
}); });
} }
handlePlayVideo(e) {
e.preventDefault();
this.props.onExpandMedia({
video: true,
url: e.target.dataset.src,
preview: e.target.src,
filename: e.target.dataset.name,
width: e.target.dataset.width,
height: e.target.dataset.height,
duration: e.target.dataset.duration,
size: e.target.dataset.size,
type: e.target.dataset.mime
});
}
handleFormButtonClick(e) { handleFormButtonClick(e) {
e.preventDefault(); e.preventDefault();
const data = { const data = {
+7 -7
View File
@@ -47,25 +47,25 @@ export default class ImagePreview extends React.PureComponent {
// Average font aspect ratio is ~0.5; File name takes 1/3 of the viewport width. // Average font aspect ratio is ~0.5; File name takes 1/3 of the viewport width.
const maxlength = Math.max(((this.state.width / REM_SIZE / 1.5) | 0) - 2, 12); const maxlength = Math.max(((this.state.width / REM_SIZE / 1.5) | 0) - 2, 12);
const fname = shortenFileName(this.props.content.name, maxlength) || '-'; const fname = shortenFileName(this.props.content.filename, maxlength) || '-';
const width = this.props.content.width || '-'; const width = this.props.content.width || '-';
const height = this.props.content.height || '-'; const height = this.props.content.height || '-';
return ( return (
<div id="image-preview"> <div id="image-preview">
<div id="image-preview-caption-panel"> <div id="image-preview-caption-panel">
{!this.props.onSendMessage ? {this.props.onSendMessage ?
<a href={this.props.content.url} download={true}> <span>{fname}</span>
:
<a href={this.props.content.url} download={this.props.content.filename}>
<i className="material-icons">file_download</i> <FormattedMessage <i className="material-icons">file_download</i> <FormattedMessage
id="download_action" defaultMessage="download" description="Call to action [download]" /> id="download_action" defaultMessage="download" description="Call to action [download]" />
</a> </a>
:
<span>{fname}</span>
} }
<a href="#" onClick={(e) => {e.preventDefault(); this.props.onClose();}}><i className="material-icons gray">close</i></a> <a href="#" onClick={(e) => {e.preventDefault(); this.props.onClose();}}><i className="material-icons gray">close</i></a>
</div> </div>
<div id="image-preview-container" ref={(node) => this.assignWidth(node)}> <div id="image-preview-container" ref={(node) => this.assignWidth(node)}>
<img src={this.props.content.url} style={size} className="image-preview" alt={this.props.content.name} /> <img src={this.props.content.url} style={size} className="image-preview" alt={this.props.content.filename} />
</div> </div>
{this.props.onSendMessage ? {this.props.onSendMessage ?
<SendMessage <SendMessage
@@ -81,7 +81,7 @@ export default class ImagePreview extends React.PureComponent {
<div> <div>
<div><b><FormattedMessage id="label_file_name" defaultMessage="File name:" <div><b><FormattedMessage id="label_file_name" defaultMessage="File name:"
description="Label for a file name" /></b></div> description="Label for a file name" /></b></div>
<div><span title={this.props.content.name}>{fname}</span></div> <div><span title={this.props.content.filename}>{fname}</span></div>
</div> </div>
<div> <div>
<div><b><FormattedMessage id="label_content_type" defaultMessage="Content type:" <div><b><FormattedMessage id="label_content_type" defaultMessage="Content type:"
+14 -2
View File
@@ -8,15 +8,27 @@ import { secondsToTime } from '../lib/strformat.js'
export default class InlineVideo extends React.PureComponent { export default class InlineVideo extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.videoRef = React.createRef();
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
if (this.props.onClick) {
// the click target has to be the image element.
this.props.onClick(e);
}
} }
render() { render() {
const duration = secondsToTime(this.props['data-duration'] / 1000); const duration = secondsToTime(this.props['data-duration'] / 1000);
const className = 'inline-video' + (this.props.onClick ? ' clickable' : '');
return ( return (
<div className="inline-video"> <div className={className}>
{React.createElement('img', this.props)} {React.createElement('img', this.props)}
{this.props.onClick ? {this.props.onClick ?
<div className="play-control" onClick={this.props.onClick}> <div className="play-control">
<i className="material-icons white bigger">play_arrow</i> <i className="material-icons white bigger">play_arrow</i>
</div> </div>
: null} : null}
+36 -3
View File
@@ -1,6 +1,9 @@
import React from 'react'; import React from 'react';
import { FormattedMessage } from 'react-intl';
import SendMessage from './send-message.jsx'; import SendMessage from './send-message.jsx';
import { bytesToHumanSize } from '../lib/strformat.js';
export default class VideoPreview extends React.PureComponent { export default class VideoPreview extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -17,7 +20,7 @@ export default class VideoPreview extends React.PureComponent {
height: this.videoRef.current.videoHeight, height: this.videoRef.current.videoHeight,
duration: (this.videoRef.current.duration * 1000) | 0, duration: (this.videoRef.current.duration * 1000) | 0,
mime: this.props.content.mime, mime: this.props.content.mime,
name: this.props.content.name name: this.props.content.filename
} }
// Capture screen from a video. // Capture screen from a video.
@@ -37,15 +40,27 @@ export default class VideoPreview extends React.PureComponent {
return null; return null;
} }
const width = this.props.content.width || '-';
const height = this.props.content.height || '-';
const controlist = this.props.onSendMessage ? 'nodownload' : '';
return ( return (
<div id="image-preview"> <div id="image-preview">
<div id="image-preview-caption-panel"> <div id="image-preview-caption-panel">
<span>{this.props.content.name}</span> <span>{this.props.content.filename}</span>
<a href="#" onClick={e => {e.preventDefault(); this.props.onClose();}}><i className="material-icons gray">close</i></a> <a href="#" onClick={e => {e.preventDefault(); this.props.onClose();}}><i className="material-icons gray">close</i></a>
</div> </div>
<div id="image-preview-container"> <div id="image-preview-container">
<video controls ref={this.videoRef} src={this.props.content.url} className="image-preview" alt={this.props.content.name} /> <video
className="image-preview"
controls controlist={controlist}
disablePictureInPicture ref={this.videoRef}
src={this.props.tinode.authorizeURL(this.props.content.url)}
poster={this.props.content.preview}
alt={this.props.content.filename} />
</div> </div>
{this.props.onSendMessage ?
<SendMessage <SendMessage
messagePrompt="add_image_caption" messagePrompt="add_image_caption"
acceptBlank={true} acceptBlank={true}
@@ -54,6 +69,24 @@ export default class VideoPreview extends React.PureComponent {
onCancelReply={this.props.onCancelReply} onCancelReply={this.props.onCancelReply}
onSendMessage={this.handleSendVideo} onSendMessage={this.handleSendVideo}
onError={this.props.onError} /> onError={this.props.onError} />
:
<div id="image-preview-footer">
<div>
<div><b><FormattedMessage id="label_file_name" defaultMessage="File name:"
description="Label for a file name" /></b></div>
<div><span title={this.props.content.filename}>{this.props.content.filename}</span></div>
</div>
<div>
<div><b><FormattedMessage id="label_content_type" defaultMessage="Content type:"
description="Label for file content type (mime)" /></b></div>
<div>{this.props.content.type}</div>
</div>
<div>
<div><b><FormattedMessage id="label_size" defaultMessage="Size:"
description="Label for file size" /></b></div>
<div>{width} &times; {height} px; {bytesToHumanSize(this.props.content.size)}</div>
</div>
</div>}
</div> </div>
); );
} }
+114 -36
View File
@@ -2747,6 +2747,7 @@ function handleImageData(el, data, attr) {
}; };
if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(data)) { if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(data)) {
attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.sanitizeUrlForMime)(attr.src, 'image')); attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.sanitizeUrlForMime)(attr.src, 'image'));
attr['data-src'] = (0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.sanitizeUrlForMime)(attr.src, 'video');
attr.alt = data.name; attr.alt = data.name;
if (attr.src) { if (attr.src) {
if (Math.max(data.width || 0, data.height || 0) > _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM) { if (Math.max(data.width || 0, data.height || 0) > _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM) {
@@ -5535,7 +5536,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
this.handleMessageUpdate = this.handleMessageUpdate.bind(this); this.handleMessageUpdate = this.handleMessageUpdate.bind(this);
this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this); this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this);
this.handleInfoReceipt = this.handleInfoReceipt.bind(this); this.handleInfoReceipt = this.handleInfoReceipt.bind(this);
this.handleImagePostview = this.handleImagePostview.bind(this); this.handleExpandMedia = this.handleExpandMedia.bind(this);
this.handleClosePreview = this.handleClosePreview.bind(this); this.handleClosePreview = this.handleClosePreview.bind(this);
this.handleFormResponse = this.handleFormResponse.bind(this); this.handleFormResponse = this.handleFormResponse.bind(this);
this.handleContextClick = this.handleContextClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this);
@@ -5651,6 +5652,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
docPreview: null, docPreview: null,
imagePreview: null, imagePreview: null,
imagePostview: null, imagePostview: null,
videoPreview: null,
videoPostview: null,
rtcPanel: null, rtcPanel: null,
typingIndicator: false, typingIndicator: false,
scrollPosition: 0, scrollPosition: 0,
@@ -5659,7 +5662,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
channel: false, channel: false,
reply: null, reply: null,
contentToEdit: null, contentToEdit: null,
showGoToLastButton: false showGoToLastButton: false,
dragging: false
}; };
} else if (nextProps.topic != prevState.topic) { } else if (nextProps.topic != prevState.topic) {
const topic = nextProps.tinode.getTopic(nextProps.topic); const topic = nextProps.tinode.getTopic(nextProps.topic);
@@ -5668,12 +5672,15 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
docPreview: null, docPreview: null,
imagePreview: null, imagePreview: null,
imagePostview: null, imagePostview: null,
videoPreview: null,
videoPostview: null,
rtcPanel: null, rtcPanel: null,
typingIndicator: false, typingIndicator: false,
scrollPosition: 0, scrollPosition: 0,
fetchingMessages: false, fetchingMessages: false,
showGoToLastButton: false, showGoToLastButton: false,
deleted: topic._deleted deleted: topic._deleted,
dragging: false
}; };
if (nextProps.forwardMessage) { if (nextProps.forwardMessage) {
nextState.reply = { nextState.reply = {
@@ -6042,10 +6049,19 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
console.info("Other change in topic: ", info.what); console.info("Other change in topic: ", info.what);
} }
} }
handleImagePostview(content) { handleExpandMedia(content) {
this.setState({ if (!content) {
imagePostview: content return;
}); }
if (content.video) {
this.setState({
videoPostview: content
});
} else {
this.setState({
imagePostview: content
});
}
} }
handleClosePreview() { handleClosePreview() {
if (this.state.imagePreview && this.state.imagePreview.url) { if (this.state.imagePreview && this.state.imagePreview.url) {
@@ -6058,7 +6074,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
imagePostview: null, imagePostview: null,
imagePreview: null, imagePreview: null,
docPreview: null, docPreview: null,
videoPreview: null videoPreview: null,
videoPostview: null
}); });
} }
handleFormResponse(action, text, data) { handleFormResponse(action, text, data) {
@@ -6217,7 +6234,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
const mime = this.state.imagePreview.mime; const mime = this.state.imagePreview.mime;
const width = this.state.imagePreview.width; const width = this.state.imagePreview.width;
const height = this.state.imagePreview.height; const height = this.state.imagePreview.height;
const fname = this.state.imagePreview.name; const fname = this.state.imagePreview.filename;
const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_17__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0; const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_17__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0;
if (blob.size > maxInbandAttachmentSize) { if (blob.size > maxInbandAttachmentSize) {
const uploader = this.props.tinode.getLargeFileHelper(); const uploader = this.props.tinode.getLargeFileHelper();
@@ -6332,7 +6349,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
videoPreview: { videoPreview: {
url: URL.createObjectURL(file), url: URL.createObjectURL(file),
blob: file, blob: file,
name: file.name, filename: file.name,
size: file.size, size: file.size,
mime: file.type mime: file.type
} }
@@ -6344,7 +6361,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
imagePreview: { imagePreview: {
url: URL.createObjectURL(scaled.blob), url: URL.createObjectURL(scaled.blob),
blob: scaled.blob, blob: scaled.blob,
name: scaled.name, filename: scaled.name,
width: scaled.width, width: scaled.width,
height: scaled.height, height: scaled.height,
size: scaled.blob.size, size: scaled.blob.size,
@@ -6551,6 +6568,12 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
content: this.state.imagePostview, content: this.state.imagePostview,
onClose: this.handleClosePreview onClose: this.handleClosePreview
}); });
} else if (this.state.videoPostview) {
component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_video_preview_jsx__WEBPACK_IMPORTED_MODULE_16__["default"], {
content: this.state.videoPostview,
tinode: this.props.tinode,
onClose: this.handleClosePreview
});
} else if (this.state.docPreview) { } else if (this.state.docPreview) {
component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_doc_preview_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_doc_preview_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], {
content: this.state.docPreview, content: this.state.docPreview,
@@ -6669,7 +6692,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
userIsWriter: this.state.isWriter, userIsWriter: this.state.isWriter,
viewportWidth: this.props.viewportWidth, viewportWidth: this.props.viewportWidth,
showContextMenu: this.handleShowMessageContextMenu, showContextMenu: this.handleShowMessageContextMenu,
onImagePreview: this.handleImagePostview, onExpandMedia: this.handleExpandMedia,
onFormResponse: this.handleFormResponse, onFormResponse: this.handleFormResponse,
onCancelUpload: this.handleCancelUpload, onCancelUpload: this.handleCancelUpload,
pickReply: this.handlePickReply, pickReply: this.handlePickReply,
@@ -11101,7 +11124,8 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
if (props.uploader) { if (props.uploader) {
props.uploader.onProgress = this.handleProgress.bind(this); props.uploader.onProgress = this.handleProgress.bind(this);
} }
this.handleImagePreview = this.handleImagePreview.bind(this); this.handleExpandImage = this.handleExpandImage.bind(this);
this.handlePlayVideo = this.handlePlayVideo.bind(this);
this.handleFormButtonClick = this.handleFormButtonClick.bind(this); this.handleFormButtonClick = this.handleFormButtonClick.bind(this);
this.handleContextClick = this.handleContextClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this);
this.handleCancelUpload = this.handleCancelUpload.bind(this); this.handleCancelUpload = this.handleCancelUpload.bind(this);
@@ -11110,23 +11134,37 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
formatMessage: props.intl.formatMessage.bind(props.intl), formatMessage: props.intl.formatMessage.bind(props.intl),
viewportWidth: props.viewportWidth, viewportWidth: props.viewportWidth,
authorizeURL: props.tinode.authorizeURL.bind(props.tinode), authorizeURL: props.tinode.authorizeURL.bind(props.tinode),
onImagePreview: this.handleImagePreview, onImagePreview: this.handleExpandImage,
onVideoPreview: this.handleImagePreview, onVideoPreview: this.handlePlayVideo,
onFormButtonClick: this.handleFormButtonClick, onFormButtonClick: this.handleFormButtonClick,
onQuoteClick: this.handleQuoteClick onQuoteClick: this.handleQuoteClick
}; };
} }
handleImagePreview(e) { handleExpandImage(e) {
e.preventDefault(); e.preventDefault();
this.props.onImagePreview({ this.props.onExpandMedia({
url: e.target.src, url: e.target.src,
filename: e.target.title, filename: e.target.dataset.name,
width: e.target.dataset.width, width: e.target.dataset.width,
height: e.target.dataset.height, height: e.target.dataset.height,
size: e.target.dataset.size, size: e.target.dataset.size,
type: e.target.dataset.mime type: e.target.dataset.mime
}); });
} }
handlePlayVideo(e) {
e.preventDefault();
this.props.onExpandMedia({
video: true,
url: e.target.dataset.src,
preview: e.target.src,
filename: e.target.dataset.name,
width: e.target.dataset.width,
height: e.target.dataset.height,
duration: e.target.dataset.duration,
size: e.target.dataset.size,
type: e.target.dataset.mime
});
}
handleFormButtonClick(e) { handleFormButtonClick(e) {
e.preventDefault(); e.preventDefault();
const data = { const data = {
@@ -13455,16 +13493,16 @@ class ImagePreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
size.maxWidth = '100%'; size.maxWidth = '100%';
size.maxHeight = '100%'; size.maxHeight = '100%';
const maxlength = Math.max((this.state.width / _config_js__WEBPACK_IMPORTED_MODULE_3__.REM_SIZE / 1.5 | 0) - 2, 12); const maxlength = Math.max((this.state.width / _config_js__WEBPACK_IMPORTED_MODULE_3__.REM_SIZE / 1.5 | 0) - 2, 12);
const fname = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_5__.shortenFileName)(this.props.content.name, maxlength) || '-'; const fname = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_5__.shortenFileName)(this.props.content.filename, maxlength) || '-';
const width = this.props.content.width || '-'; const width = this.props.content.width || '-';
const height = this.props.content.height || '-'; const height = this.props.content.height || '-';
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
id: "image-preview" id: "image-preview"
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
id: "image-preview-caption-panel" id: "image-preview-caption-panel"
}, !this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { }, this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, fname) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
href: this.props.content.url, href: this.props.content.url,
download: true download: this.props.content.filename
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
className: "material-icons" className: "material-icons"
}, "file_download"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { }, "file_download"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
@@ -13473,7 +13511,7 @@ class ImagePreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
"type": 0, "type": 0,
"value": "download" "value": "download"
}] }]
})) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, fname), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
href: "#", href: "#",
onClick: e => { onClick: e => {
e.preventDefault(); e.preventDefault();
@@ -13488,7 +13526,7 @@ class ImagePreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
src: this.props.content.url, src: this.props.content.url,
style: size, style: size,
className: "image-preview", className: "image-preview",
alt: this.props.content.name alt: this.props.content.filename
})), this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { })), this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], {
messagePrompt: "add_image_caption", messagePrompt: "add_image_caption",
acceptBlank: true, acceptBlank: true,
@@ -13506,7 +13544,7 @@ class ImagePreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
"value": "File name:" "value": "File name:"
}] }]
}))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
title: this.props.content.name title: this.props.content.filename
}, fname))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { }, fname))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "label_content_type", id: "label_content_type",
defaultMessage: [{ defaultMessage: [{
@@ -13680,14 +13718,21 @@ __webpack_require__.r(__webpack_exports__);
class InlineVideo extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { class InlineVideo extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
constructor(props) { constructor(props) {
super(props); super(props);
this.videoRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
if (this.props.onClick) {
this.props.onClick(e);
}
} }
render() { render() {
const duration = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_1__.secondsToTime)(this.props['data-duration'] / 1000); const duration = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_1__.secondsToTime)(this.props['data-duration'] / 1000);
const className = 'inline-video' + (this.props.onClick ? ' clickable' : '');
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
className: "inline-video" className: className
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.props), this.props.onClick ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.props), this.props.onClick ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
className: "play-control", className: "play-control"
onClick: this.props.onClick
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
className: "material-icons white bigger" className: "material-icons white bigger"
}, "play_arrow")) : null, duration ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { }, "play_arrow")) : null, duration ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
@@ -16381,7 +16426,12 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ }); /* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* 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__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _send_message_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./send-message.jsx */ "./src/widgets/send-message.jsx"); /* 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 _send_message_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./send-message.jsx */ "./src/widgets/send-message.jsx");
/* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js");
class VideoPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { class VideoPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
@@ -16397,7 +16447,7 @@ class VideoPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
height: this.videoRef.current.videoHeight, height: this.videoRef.current.videoHeight,
duration: this.videoRef.current.duration * 1000 | 0, duration: this.videoRef.current.duration * 1000 | 0,
mime: this.props.content.mime, mime: this.props.content.mime,
name: this.props.content.name name: this.props.content.filename
}; };
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
canvas.width = params.width; canvas.width = params.width;
@@ -16410,11 +16460,14 @@ class VideoPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
if (!this.props.content) { if (!this.props.content) {
return null; return null;
} }
const width = this.props.content.width || '-';
const height = this.props.content.height || '-';
const controlist = this.props.onSendMessage ? 'nodownload' : '';
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
id: "image-preview" id: "image-preview"
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
id: "image-preview-caption-panel" id: "image-preview-caption-panel"
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.content.name), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.content.filename), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
href: "#", href: "#",
onClick: e => { onClick: e => {
e.preventDefault(); e.preventDefault();
@@ -16425,12 +16478,15 @@ class VideoPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
}, "close"))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { }, "close"))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
id: "image-preview-container" id: "image-preview-container"
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", {
controls: true,
ref: this.videoRef,
src: this.props.content.url,
className: "image-preview", className: "image-preview",
alt: this.props.content.name controls: true,
})), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_send_message_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { controlist: controlist,
disablePictureInPicture: true,
ref: this.videoRef,
src: this.props.tinode.authorizeURL(this.props.content.url),
poster: this.props.content.preview,
alt: this.props.content.filename
})), this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], {
messagePrompt: "add_image_caption", messagePrompt: "add_image_caption",
acceptBlank: true, acceptBlank: true,
tinode: this.props.tinode, tinode: this.props.tinode,
@@ -16438,7 +16494,29 @@ class VideoPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
onCancelReply: this.props.onCancelReply, onCancelReply: this.props.onCancelReply,
onSendMessage: this.handleSendVideo, onSendMessage: this.handleSendVideo,
onError: this.props.onError onError: this.props.onError
})); }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
id: "image-preview-footer"
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "label_file_name",
defaultMessage: [{
"type": 0,
"value": "File name:"
}]
}))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
title: this.props.content.filename
}, this.props.content.filename))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "label_content_type",
defaultMessage: [{
"type": 0,
"value": "Content type:"
}]
}))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.props.content.type)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "label_size",
defaultMessage: [{
"type": 0,
"value": "Size:"
}]
}))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, width, " \xD7 ", height, " px; ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.bytesToHumanSize)(this.props.content.size)))));
} }
} }
; ;
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long