more components updated/translated
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
// Single message, sent or received.
|
||||
import React from 'react';
|
||||
import {Drafty} from 'tinode-sdk'
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Drafty } from 'tinode-sdk'
|
||||
|
||||
import Attachment from './attachment.jsx';
|
||||
import LetterTile from './letter-tile.jsx';
|
||||
import ReceivedMarker from './received-marker.jsx'
|
||||
|
||||
/* Single message, sent or received. */
|
||||
import { REM_SIZE } from '../config.js';
|
||||
import { fitImageSize } from '../lib/blob-helpers.js';
|
||||
|
||||
export default class ChatMessage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -50,17 +54,16 @@ export default class ChatMessage extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
var elementKey = 0;
|
||||
|
||||
var formatter = function(style, data, values) {
|
||||
let elementKey = 0;
|
||||
const formatter = function(style, data, values) {
|
||||
elementKey += 1;
|
||||
var el = Drafty.tagName(style);
|
||||
let el = Drafty.tagName(style);
|
||||
if (el) {
|
||||
var attr = Drafty.attrValue(style, data) || {};
|
||||
let attr = Drafty.attrValue(style, data) || {};
|
||||
attr.key = elementKey;
|
||||
if (style == 'IM') {
|
||||
// Additional processing for images
|
||||
var dim = fitImageSize(data.width, data.height,
|
||||
let dim = fitImageSize(data.width, data.height,
|
||||
Math.min(this.props.viewportWidth - REM_SIZE * 4, REM_SIZE * 36), REM_SIZE * 24, false);
|
||||
attr.className = 'inline-image';
|
||||
attr.style = dim ? { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px' } : null;
|
||||
@@ -95,7 +98,10 @@ export default class ChatMessage extends React.Component {
|
||||
}, this);
|
||||
content = React.createElement('span', null, Drafty.format(content, formatter, this));
|
||||
} else if (typeof content != 'string') {
|
||||
content = <span><i className="material-icons">error_outline</i> <i>invalid content</i></span>
|
||||
content = <span><i className="material-icons">error_outline</i> <i>
|
||||
<FormattedMessage id="invalid_content"
|
||||
defaultMessage="invalid content" description="Shown when message is unreadable" />
|
||||
</i></span>
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
+10
-10
@@ -1,10 +1,10 @@
|
||||
// A single topic or user.
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import LetterTile from './letter-tile.jsx';
|
||||
import UnreadBadge from './unread-badge.jsx';
|
||||
|
||||
/* A single topic or user */
|
||||
|
||||
export default class Contact extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -28,20 +28,20 @@ export default class Contact extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
var title = this.props.title;
|
||||
let title = this.props.title;
|
||||
if (!title) {
|
||||
title = <i>unknown</i>;
|
||||
title = <i><FormattedMessage id="unnamed_topic" /></i>;
|
||||
} else if (title.length > 30) {
|
||||
// FIXME: this is wrong for RTL languages.
|
||||
// FIXME: this is probably wrong for RTL languages.
|
||||
title = title.substring(0, 28) + '...';
|
||||
}
|
||||
var online = this.props.now ? 'online' : 'offline';
|
||||
var avatar = this.props.avatar ? this.props.avatar : true;
|
||||
var badges = [];
|
||||
let online = this.props.now ? 'online' : 'offline';
|
||||
let avatar = this.props.avatar ? this.props.avatar : true;
|
||||
let badges = [];
|
||||
if (this.props.badges && this.props.badges.length > 0) {
|
||||
var count = 0;
|
||||
let count = 0;
|
||||
this.props.badges.map(function(b) {
|
||||
var style = 'badge' + (b.color ? ' ' + b.color : '');
|
||||
let style = 'badge' + (b.color ? ' ' + b.color : '');
|
||||
badges.push(<span className={style} key={count}>{b.name}</span>);
|
||||
count ++;
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Context Menu: popup/dropdown menu.
|
||||
import React from 'react';
|
||||
import ReactDom from 'react-dom';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { REM_SIZE } from '../config.js';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* GroupMembers: control for managing a list of group members */
|
||||
|
||||
// GroupMembers: control for managing a list of group members.
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import ChipInput from './chip-input.jsx';
|
||||
import ContactList from './contact-list.jsx';
|
||||
@@ -156,8 +156,12 @@ export default class GroupManager extends React.Component {
|
||||
showUnread={false}
|
||||
onTopicSelected={this.handleContactSelected} />
|
||||
<div id="group-manager-buttons" className="panel-form-row">
|
||||
<button className="blue" onClick={this.handleSubmit}>OK</button>
|
||||
<button className="white" onClick={this.handleCancel}>Cancel</button>
|
||||
<button className="blue" onClick={this.handleSubmit}>
|
||||
<FormattedMessage id="button_ok" defaultMessage="OK" description="Button [OK]" />
|
||||
</button>
|
||||
<button className="white" onClick={this.handleCancel}>
|
||||
<FormattedMessage id="button_cancel" defaultMessage="Cancel" description="Button [Cancel]" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { REM_SIZE } from '../config.js';
|
||||
import { fitImageSize } from '../lib/blob-helpers.js';
|
||||
import { bytesToHumanSize } from '../lib/strformat.js';
|
||||
|
||||
export default class ImagePreview extends React.PureComponent {
|
||||
constructor(props) {
|
||||
@@ -43,10 +48,19 @@ export default class ImagePreview extends React.PureComponent {
|
||||
<img src={this.props.content.url} style={size} />
|
||||
</div>
|
||||
<div id="image-preview-footer">
|
||||
<div><div><b>File name</b>:</div><div><span title={this.props.content.filename}>{filename}</span></div></div>
|
||||
<div><div><b>Content type</b>:</div><div>{this.props.content.type}</div></div>
|
||||
<div>
|
||||
<div><b>Size</b>:</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}>{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>{this.props.content.width} × {this.props.content.height} px; {bytesToHumanSize(this.props.content.size)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// In-place text editor. Shows text with an icon which toggles it into an input field.
|
||||
import React from 'react';
|
||||
import ReactDom from 'react-dom';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import VisiblePassword from './visible-password.jsx';
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// Send message form.
|
||||
import React from 'react';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { Drafty } from 'tinode-sdk';
|
||||
|
||||
import { KEYPRESS_DELAY } from '../config.js';
|
||||
import { KEYPRESS_DELAY, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE } from '../config.js';
|
||||
import { SUPPORTED_IMAGE_FORMATS, filePasted, imageFileToBase64, imageFileScaledToBase64 } from '../lib/blob-helpers.js';
|
||||
import { bytesToHumanSize } from '../lib/strformat.js';
|
||||
|
||||
const messages = defineMessages({
|
||||
'messaging_disabled': {
|
||||
@@ -14,7 +17,17 @@ const messages = defineMessages({
|
||||
id: 'new_message_prompt',
|
||||
defaultMessage: 'New message',
|
||||
description: 'Prompt in SendMessage in read-only topic'
|
||||
}
|
||||
},
|
||||
'file_attachment_too_large': {
|
||||
id: 'file_attachment_too_large',
|
||||
defaultMessage: 'The file size {size} exceeds the {limit} limit.',
|
||||
description: 'Error message when attachment is too large'
|
||||
},
|
||||
'cannot_initiate_upload': {
|
||||
id: 'cannot_initiate_file_upload',
|
||||
defaultMessage: 'Cannot initiate file upload.',
|
||||
description: 'Generic error messagewhen attachment fails'
|
||||
},
|
||||
});
|
||||
|
||||
class SendMessage extends React.PureComponent {
|
||||
@@ -99,17 +112,18 @@ class SendMessage extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleAttachFile(e) {
|
||||
const {formatMessage} = this.props.intl;
|
||||
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');
|
||||
this.props.onError(formatMessage(messages.file_attachment_too_large,
|
||||
{size: bytesToHumanSize(file.size), limit: bytesToHumanSize(MAX_EXTERN_ATTACHMENT_SIZE)}), '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.");
|
||||
this.props.onError(formatMessage(messages.cannot_initiate_upload));
|
||||
return;
|
||||
}
|
||||
// Format data and initiate upload.
|
||||
|
||||
Reference in New Issue
Block a user