more fixes
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "tinode-webapp",
|
||||
"description": "Tinode messenger for the web",
|
||||
"version": "0.15.8-rc1",
|
||||
"version": "0.15.9-rc1",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.1.2",
|
||||
"@babel/preset-env": "^7.1.0",
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
"sign_in_button": "Sign in",
|
||||
"label_client": "Client:",
|
||||
"label_server": "Server:",
|
||||
"online_now": "online now",
|
||||
"last_seen_timestamp": "Last seen",
|
||||
"title_not_found": "Not found",
|
||||
"unnamed_topic": "Unnamed",
|
||||
"messages_not_readable": "no access to messages",
|
||||
"label_server_to_use": "Server to use:",
|
||||
"label_wire_transport": "Wire transport:",
|
||||
"button_update": "Update",
|
||||
"sidepanel_title_login": "Sign In",
|
||||
"sidepanel_title_register": "Create Account",
|
||||
"sidepanel_title_settings": "Settings",
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
"sign_in_button": "Войти",
|
||||
"label_client": "Клиент:",
|
||||
"label_server": "Сервер:",
|
||||
"online_now": "онлайн",
|
||||
"last_seen_timestamp": "Был активен",
|
||||
"title_not_found": "Не найден",
|
||||
"unnamed_topic": "Без названия",
|
||||
"messages_not_readable": "нет доступа к сообщениям",
|
||||
"label_server_to_use": "Использовать сервер:",
|
||||
"label_wire_transport": "Соединение:",
|
||||
"button_update": "Применить",
|
||||
"sidepanel_title_login": "Авторизация",
|
||||
"sidepanel_title_register": "Зарегистрироваться",
|
||||
"sidepanel_title_settings": "Настройки",
|
||||
|
||||
+9
-3
@@ -11,10 +11,16 @@ import ru from './i18n/ru.json';
|
||||
|
||||
import TinodeWeb from './views/tinode-web.jsx';
|
||||
|
||||
import HashNavigation from './lib/navigation.js';
|
||||
|
||||
const {params} = HashNavigation.parseUrlHash(window.location.hash);
|
||||
const language = (params && params.hl) ||
|
||||
(navigator.languages && navigator.languages[0]) ||
|
||||
navigator.language ||
|
||||
navigator.userLanguage;
|
||||
|
||||
ReactDOM.render(
|
||||
<IntlProvider
|
||||
locale={navigator.language}
|
||||
messages={en} >
|
||||
<IntlProvider locale={language} messages={en} >
|
||||
<TinodeWeb />
|
||||
</IntlProvider>,
|
||||
document.getElementById('mountPoint')
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
// This is a generated file. Don't edit.
|
||||
|
||||
export const PACKAGE_VERSION = "0.15.8-rc1";
|
||||
export const PACKAGE_VERSION = "0.15.9-rc1";
|
||||
|
||||
@@ -95,27 +95,28 @@ export default class CreateAccountView extends React.PureComponent {
|
||||
<div className="panel-form-row">
|
||||
<FormattedMessage id="full_name_prompt" defaultMessage="Full name, e.g. John Doe"
|
||||
description="Input placeholder for person's full name">{
|
||||
<input type="text" placeholder={full_name_prompt} autoComplete="name"
|
||||
(full_name_prompt) => <input type="text" placeholder={full_name_prompt} autoComplete="name"
|
||||
value={this.state.fn} onChange={this.handleFnChange} required/>
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
<div className="panel-form-row">
|
||||
<FormattedMessage id="email_prompt" defaultMessage="Email, e.g. jdoe@example.com"
|
||||
description="Input placeholder for email entry">{
|
||||
<input type="email" placeholder={email_prompt} autoComplete="email"
|
||||
(email_prompt) => <input type="email" placeholder={email_prompt} autoComplete="email"
|
||||
value={this.state.email} onChange={this.handleEmailChange} required/>
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
<div className="panel-form-row">
|
||||
<CheckBox id="save-token" name="save-token" checked={this.state.saveToken}
|
||||
onChange={this.handleToggleSaveToken} />
|
||||
<FormattedMessage id="stay_logged_in">
|
||||
{(stay_logged_in) => <label htmlFor="save-token"> {stay_logged_in}</label>}
|
||||
</FormattedMessage>
|
||||
<FormattedMessage id="stay_logged_in">{
|
||||
(stay_logged_in) => <label htmlFor="save-token"> {stay_logged_in}</label>
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
<div className="dialog-buttons">
|
||||
<button className={submitClasses} type="submit">
|
||||
<FormattedMessage id="sign_up_button" defaultMessage="Sign up" />
|
||||
<FormattedMessage id="sign_up_button" defaultMessage="Sign up"
|
||||
description="Create account button [Sign Up]" />
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
+55
-23
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import ChatMessage from '../widgets/chat-message.jsx';
|
||||
import ErrorPanel from '../widgets/error-panel.jsx';
|
||||
@@ -9,9 +10,27 @@ import LoadSpinner from '../widgets/load-spinner.jsx';
|
||||
import LogoView from './logo-view.jsx';
|
||||
import SendMessage from '../widgets/send-message.jsx';
|
||||
|
||||
const NOT_FOUND_TOPIC_TITLE = "Not found";
|
||||
import { shortDateFormat } from '../lib/strformat.js';
|
||||
|
||||
export default class MessagesView extends React.Component {
|
||||
const messages = defineMessages({
|
||||
online_now: {
|
||||
id: 'online_now',
|
||||
defaultMessage: 'online now',
|
||||
description: 'Indicator that the user or topic is currently online',
|
||||
},
|
||||
last_seen: {
|
||||
id: 'last_seen_timestamp',
|
||||
defaultMessage: 'Last seen',
|
||||
description: 'Label for the timestamp of when the user or topic was last online'
|
||||
},
|
||||
'not_found': {
|
||||
id: 'title_not_found',
|
||||
defaultMessage: 'Not found',
|
||||
description: 'Title shown when topic is not found'
|
||||
}
|
||||
});
|
||||
|
||||
class MessagesView extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -162,8 +181,9 @@ export default class MessagesView extends React.Component {
|
||||
})
|
||||
.catch((err) => {
|
||||
this.props.onError(err.message, 'err');
|
||||
const {formatMessage} = this.props.intl;
|
||||
this.setState({
|
||||
title: NOT_FOUND_TOPIC_TITLE,
|
||||
title: formatMessage(messages.not_found),
|
||||
avatar: null,
|
||||
readOnly: true,
|
||||
writeOnly: true,
|
||||
@@ -349,21 +369,24 @@ export default class MessagesView extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
var component = null;
|
||||
const {formatMessage} = this.props.intl;
|
||||
|
||||
let component;
|
||||
|
||||
if (this.state.topic) {
|
||||
var messageNodes = [];
|
||||
var topic = this.props.tinode.getTopic(this.state.topic);
|
||||
var groupTopic = topic.getType() == 'grp';
|
||||
var previousFrom = null;
|
||||
for (var i=0; i<this.state.messages.length; i++) {
|
||||
var msg = this.state.messages[i];
|
||||
var nextFrom = null;
|
||||
let messageNodes = [];
|
||||
let topic = this.props.tinode.getTopic(this.state.topic);
|
||||
let groupTopic = topic.getType() == 'grp';
|
||||
let previousFrom = null;
|
||||
for (let i=0; i<this.state.messages.length; i++) {
|
||||
let msg = this.state.messages[i];
|
||||
let nextFrom = null;
|
||||
|
||||
if (i + 1 < this.state.messages.length) {
|
||||
nextFrom = this.state.messages[i+1].from
|
||||
}
|
||||
|
||||
var sequence = 'single';
|
||||
let sequence = 'single';
|
||||
if (msg.from == previousFrom) {
|
||||
if (msg.from == nextFrom) {
|
||||
sequence = 'middle';
|
||||
@@ -375,12 +398,12 @@ export default class MessagesView extends React.Component {
|
||||
}
|
||||
previousFrom = msg.from;
|
||||
|
||||
var isReply = !(msg.from == this.props.myUserId);
|
||||
var deliveryStatus = topic.msgStatus(msg);
|
||||
let isReply = !(msg.from == this.props.myUserId);
|
||||
let deliveryStatus = topic.msgStatus(msg);
|
||||
|
||||
var userName, userAvatar, userFrom, chatBoxClass;
|
||||
let userName, userAvatar, userFrom, chatBoxClass;
|
||||
if (groupTopic) {
|
||||
var user = topic.userDesc(msg.from);
|
||||
let user = topic.userDesc(msg.from);
|
||||
if (user && user.public) {
|
||||
userName = user.public.fn;
|
||||
userAvatar = makeImageUrl(user.public.photo);
|
||||
@@ -411,14 +434,14 @@ export default class MessagesView extends React.Component {
|
||||
let cont = this.props.tinode.getMeTopic().getContact(this.state.topic);
|
||||
if (cont && Tinode.topicType(cont.topic) == 'p2p') {
|
||||
if (cont.online) {
|
||||
lastSeen = "online now";
|
||||
lastSeen = formatMessage(messages.online_now);
|
||||
} else if (cont.seen) {
|
||||
lastSeen = "Last active: " + shortDateFormat(cont.seen.when);
|
||||
// TODO(gene): also handle user agent in c.seen.ua
|
||||
lastSeen = formatMessage(messages.last_seen) + ": " + shortDateFormat(cont.seen.when);
|
||||
// TODO: also handle user agent in c.seen.ua
|
||||
}
|
||||
}
|
||||
var avatar = this.state.avatar || true;
|
||||
var online = this.props.online ? 'online' + (this.state.typingIndicator ? ' typing' : '') : 'offline';
|
||||
let avatar = this.state.avatar || true;
|
||||
let online = this.props.online ? 'online' + (this.state.typingIndicator ? ' typing' : '') : 'offline';
|
||||
|
||||
component = (
|
||||
<div id="topic-view" className={this.props.hideSelf ? 'nodisplay' : null}>
|
||||
@@ -437,7 +460,11 @@ export default class MessagesView extends React.Component {
|
||||
<span className={online} />
|
||||
</div>
|
||||
<div id="topic-title-group">
|
||||
<div id="topic-title" className="panel-title">{this.state.title || <i>Unknown</i>}</div>
|
||||
<div id="topic-title" className="panel-title">{
|
||||
this.state.title ||
|
||||
<i><FormattedMessage id="unnamed_topic" defaultMessage="Unnamed"
|
||||
description="Title shown when the topic has no name" /></i>
|
||||
}</div>
|
||||
<div id="topic-last-seen">{lastSeen}</div>
|
||||
</div>
|
||||
{groupTopic ?
|
||||
@@ -466,7 +493,10 @@ export default class MessagesView extends React.Component {
|
||||
</div>
|
||||
{this.state.writeOnly ?
|
||||
<div id="write-only-background">
|
||||
<div id="write-only-note">no access to messages</div>
|
||||
<div id="write-only-note">
|
||||
<FormattedMessage id="messages_not_readable" defaultMessage="no access to messages"
|
||||
description="Message shown in topic without the read access" />
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
null
|
||||
@@ -493,3 +523,5 @@ export default class MessagesView extends React.Component {
|
||||
return component;
|
||||
}
|
||||
};
|
||||
|
||||
export default injectIntl(MessagesView);
|
||||
|
||||
@@ -3,6 +3,8 @@ import React from 'react';
|
||||
|
||||
import VisiblePassword from '../widgets/visible-password.jsx';
|
||||
|
||||
import HashNavigation from '../lib/navigation.js';
|
||||
|
||||
export default class PasswordResetView extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -18,7 +20,7 @@ export default class PasswordResetView extends React.PureComponent {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let parsed = parseUrlHash(window.location.hash);
|
||||
let parsed = HashNavigation.parseUrlHash(window.location.hash);
|
||||
this.setState({token: parsed.params.token, scheme: parsed.params.scheme});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Tinode config panel.
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import HostSelector from '../widgets/host-selector.jsx';
|
||||
|
||||
@@ -35,10 +36,10 @@ export default class SettingsView extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
var names = {def: "default", ws: "websocket", lp: "long polling"};
|
||||
const names = {def: "default", ws: "websocket", lp: "long polling"};
|
||||
var transportOptions = [];
|
||||
var instance = this;
|
||||
['def', 'ws', 'lp'].map(function(item){
|
||||
['def', 'ws', 'lp'].map(function(item) {
|
||||
var id = 'transport-' + item;
|
||||
var name = names[item];
|
||||
transportOptions.push(
|
||||
@@ -54,12 +55,18 @@ export default class SettingsView extends React.PureComponent {
|
||||
return (
|
||||
<form id="settings-form" className="panel-form" onSubmit={this.handleSubmit}>
|
||||
<div className="panel-form-row">
|
||||
<label className="small">Server to use:</label>
|
||||
<label className="small">
|
||||
<FormattedMessage id="label_server_to_use" defaultMessage="Server to use:"
|
||||
description="Label for server selector in SettingsView" />
|
||||
</label>
|
||||
</div>
|
||||
<HostSelector serverAddress={this.state.serverAddress}
|
||||
onServerAddressChange={this.handleServerAddressChange} />
|
||||
<div className="panel-form-row">
|
||||
<label className="small">Wire transport:</label>
|
||||
<label className="small">
|
||||
<FormattedMessage id="label_wire_transport" defaultMessage="Wire transport:"
|
||||
description="Label for wire transport selection in SettingsView" />
|
||||
</label>
|
||||
</div>
|
||||
<div className="panel-form-row">
|
||||
<ul className="quoted">
|
||||
@@ -67,7 +74,10 @@ export default class SettingsView extends React.PureComponent {
|
||||
</ul>
|
||||
</div>
|
||||
<div className="dialog-buttons">
|
||||
<button type="submit" className="blue">Update</button>
|
||||
<button type="submit" className="blue">
|
||||
<FormattedMessage id="button_update" defaultMessage="Update"
|
||||
description="Button [Update]" />
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { KNOWN_HOSTS } from '../config.js';
|
||||
|
||||
/* Combobox for selecting host name */
|
||||
|
||||
export default class HostSelector extends React.PureComponent {
|
||||
@@ -28,8 +30,8 @@ export default class HostSelector extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
var hostOptions = [];
|
||||
for (var key in KNOWN_HOSTS) {
|
||||
var item = KNOWN_HOSTS[key];
|
||||
for (let key in KNOWN_HOSTS) {
|
||||
let item = KNOWN_HOSTS[key];
|
||||
hostOptions.push(
|
||||
<option key={item} value={item} />
|
||||
);
|
||||
|
||||
+34
-11
File diff suppressed because one or more lines are too long
+6
-6
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user