// Send message form. import React from 'react'; export default class SendMessage extends React.PureComponent { constructor(props) { super(props); this.state = { message: '', // Make initial keypress time as if it happened 5001 milliseconds in the past. keypressTimestamp: new Date().getTime() - KEYPRESS_DELAY - 1 }; this.handlePasteEvent = this.handlePasteEvent.bind(this); this.handleAttachImage = this.handleAttachImage.bind(this); this.handleAttachFile = this.handleAttachFile.bind(this); this.handleSend = this.handleSend.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleMessageTyping = this.handleMessageTyping.bind(this); } componentDidMount() { this.pasteFile.addEventListener('paste', this.handlePasteEvent, false); } componentWillUnmount() { this.pasteFile.removeEventListener('paste', this.handlePasteEvent, false) } handlePasteEvent(e) { if (this.props.disabled) { return; } // FIXME: handle large files too. if (filePasted(e, (bits, mime, width, height, fname) => { this.props.sendMessage(Drafty.insertImage(null, 0, mime, bits, width, height, fname)); }, (mime, bits, fname) => { this.props.sendMessage(Drafty.attachFile(null, mime, bits, fname)); }, this.props.onError)) { // If a file was pasted, don't paste base64 data into input field. e.preventDefault(); } } handleAttachImage(e) { if (e.target.files && e.target.files.length > 0) { let file = e.target.files[0]; // Check if the uploaded file is indeed an image and if it isn't too large. if (file.size > MAX_INBAND_ATTACHMENT_SIZE || SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) { // Convert image for size or format. imageFileScaledToBase64(file, MAX_IMAGE_DIM, MAX_IMAGE_DIM, false, // Success (bits, mime, width, height, fname) => { this.props.sendMessage(Drafty.insertImage(null, 0, mime, bits, width, height, fname)); }, // Failure (err) => { this.props.onError(err, 'err'); }); } else { // Image can be uploaded as is. No conversion is needed. imageFileToBase64(file, // Success (bits, mime, width, height, fname) => { this.props.sendMessage(Drafty.insertImage(null, 0, mime, bits, width, height, fname)); }, // Failure (err) => { this.props.onError(err, 'err'); } ); } } // Clear the value so the same file can be uploaded again. e.target.value = ''; } handleAttachFile(e) { if (e.target.files && e.target.files.length > 0) { var file = e.target.files[0]; if (file.size > MAX_EXTERN_ATTACHMENT_SIZE) { // Too large. this.props.onError("The file size " + bytesToHumanSize(file.size) + " exceeds the " + bytesToHumanSize(MAX_EXTERN_ATTACHMENT_SIZE) + " limit.", 'err'); } else if (file.size > MAX_INBAND_ATTACHMENT_SIZE) { // Too large to send inband - uploading out of band and sending as a link. let uploader = this.props.tinode.getLargeFileHelper(); if (!uploader) { this.props.onError("Cannot initiate file upload."); return; } // Format data and initiate upload. let uploadCompletionPromise = uploader.upload(file); let msg = Drafty.attachFile(null, file.type, null, file.name, file.size, uploadCompletionPromise); // Pass data and the uploader to the TinodeWeb. this.props.sendMessage(msg, uploadCompletionPromise, uploader); } else { // Small enough to send inband. fileToBase64(file, (mime, bits, fname) => { this.props.sendMessage(Drafty.attachFile(null, mime, bits, fname)); }, this.props.onError ); } } // Clear the value so the same file can be uploaded again. e.target.value = ''; } handleSend() { var message = this.state.message.trim(); if (message) { this.props.sendMessage(this.state.message.trim()); this.setState({message: ''}); } } /* Send on Enter key */ handleKeyPress(e) { // Remove this if you don't want Enter to trigger send if (e.key === 'Enter') { // Have Shift-Enter insert a line break instead if (!e.shiftKey) { e.preventDefault(); e.stopPropagation(); this.handleSend(); } } } handleMessageTyping(e) { var newState = {message: e.target.value}; var now = new Date().getTime(); if (now - this.state.keypressTimestamp > KEYPRESS_DELAY) { var topic = this.props.tinode.getTopic(this.props.topic); if (topic.isSubscribed()) { topic.noteKeyPress(); } newState.keypressTimestamp = now; } this.setState(newState); } render() { var prompt = this.props.disabled ? "Messaging disabled" : "New message"; var instance = this; return (
{this.props.disabled ? photo : photo } {this.props.disabled ? attach_file : attach_file }