all components are translated now
This commit is contained in:
@@ -1448,12 +1448,24 @@ ul.tabbar li.active > a:after {
|
|||||||
color: #660;
|
color: #660;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge.blue {
|
||||||
|
border-color: #339;
|
||||||
|
background-color: #eef;
|
||||||
|
color: #339;
|
||||||
|
}
|
||||||
|
|
||||||
.badge.red {
|
.badge.red {
|
||||||
border-color: #933;
|
border-color: #933;
|
||||||
background-color: #fee;
|
background-color: #fee;
|
||||||
color: #933;
|
color: #933;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge.magenta {
|
||||||
|
border-color: #939;
|
||||||
|
background-color: #fef;
|
||||||
|
color: #939;
|
||||||
|
}
|
||||||
|
|
||||||
/* Letter tile base style, responsive square box */
|
/* Letter tile base style, responsive square box */
|
||||||
.lettertile {
|
.lettertile {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -36,7 +36,7 @@ let messages = globSync(MESSAGES_PATTERN)
|
|||||||
|
|
||||||
let filename = path.join(LANG_DIR, DEFAULT_TRANSLATION);
|
let filename = path.join(LANG_DIR, DEFAULT_TRANSLATION);
|
||||||
mkdirpSync(path.dirname(filename));
|
mkdirpSync(path.dirname(filename));
|
||||||
fs.writeFileSync(filename, JSON.stringify(messages, null, 2));
|
fs.writeFileSync(filename, JSON.stringify(messages, null, 2)+"\n");
|
||||||
|
|
||||||
// Find messages present in en.json but missing in translations and vice versa.
|
// Find messages present in en.json but missing in translations and vice versa.
|
||||||
// Mark missing or obsolete messages as such in translation files.
|
// Mark missing or obsolete messages as such in translation files.
|
||||||
@@ -64,7 +64,7 @@ globSync(LANG_PATTERN)
|
|||||||
translated[ent[0]] = val;
|
translated[ent[0]] = val;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fs.writeFileSync(filename, JSON.stringify(translated, null, 2));
|
fs.writeFileSync(filename, JSON.stringify(translated, null, 2)+"\n");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -94,4 +94,4 @@ messages = globSync(LANG_PATTERN)
|
|||||||
|
|
||||||
// Write file with all translations combined.
|
// Write file with all translations combined.
|
||||||
mkdirpSync(path.dirname(FINAL_FILE));
|
mkdirpSync(path.dirname(FINAL_FILE));
|
||||||
fs.writeFileSync(FINAL_FILE, JSON.stringify(messages, null, 2));
|
fs.writeFileSync(FINAL_FILE, JSON.stringify(messages, null, 2)+"\n");
|
||||||
|
|||||||
+18
-1
@@ -48,6 +48,11 @@
|
|||||||
"tabtitle_new_group": "new group",
|
"tabtitle_new_group": "new group",
|
||||||
"tabtitle_group_by_id": "by id",
|
"tabtitle_group_by_id": "by id",
|
||||||
"search_for_contacts": "Use search to find contacts",
|
"search_for_contacts": "Use search to find contacts",
|
||||||
|
"new_password_placeholder": "Enter new password",
|
||||||
|
"label_reset_password": "Send a password reset email:",
|
||||||
|
"credential_email_prompt": "Your registration email",
|
||||||
|
"button_reset": "Reset",
|
||||||
|
"button_send_request": "Send request",
|
||||||
"label_server_to_use": "Server to use:",
|
"label_server_to_use": "Server to use:",
|
||||||
"label_wire_transport": "Wire transport:",
|
"label_wire_transport": "Wire transport:",
|
||||||
"button_update": "Update",
|
"button_update": "Update",
|
||||||
@@ -64,6 +69,8 @@
|
|||||||
"numeric_confirmation_code_prompt": "Numbers only",
|
"numeric_confirmation_code_prompt": "Numbers only",
|
||||||
"button_confirm": "Confirm",
|
"button_confirm": "Confirm",
|
||||||
"invalid_content": "invalid content",
|
"invalid_content": "invalid content",
|
||||||
|
"badge_you": "you",
|
||||||
|
"badge_owner": "owner",
|
||||||
"menu_item_info": "Info",
|
"menu_item_info": "Info",
|
||||||
"menu_item_clear_messages": "Clear messages",
|
"menu_item_clear_messages": "Clear messages",
|
||||||
"menu_item_clear_messages_for_all": "Clear for All",
|
"menu_item_clear_messages_for_all": "Clear for All",
|
||||||
@@ -75,13 +82,23 @@
|
|||||||
"menu_item_unblock": "Unblock",
|
"menu_item_unblock": "Unblock",
|
||||||
"menu_item_block": "Block",
|
"menu_item_block": "Block",
|
||||||
"menu_item_member_delete": "Remove",
|
"menu_item_member_delete": "Remove",
|
||||||
"title_group_members": "Group members",
|
"action_cancel": "cancel",
|
||||||
|
"upload_finishing": "finishing...",
|
||||||
|
"no_contacts": "You have no contacts :-(",
|
||||||
|
"contacts_not_found_short": "No contacts match '{query}'",
|
||||||
|
"title_group_members": "Group Members",
|
||||||
|
"title_all_contacts": "All Contacts",
|
||||||
"button_ok": "OK",
|
"button_ok": "OK",
|
||||||
"button_cancel": "Cancel",
|
"button_cancel": "Cancel",
|
||||||
"download_action": "download",
|
"download_action": "download",
|
||||||
"label_file_name": "File name:",
|
"label_file_name": "File name:",
|
||||||
"label_content_type": "Content type:",
|
"label_content_type": "Content type:",
|
||||||
"label_size": "Size:",
|
"label_size": "Size:",
|
||||||
|
"error_invalid_id": "Invalid ID",
|
||||||
|
"group_user_id_prompt": "Group or User ID",
|
||||||
|
"button_subscribe": "Subscribe",
|
||||||
|
"topic_name_editing_placeholder": "Freeform name of the group",
|
||||||
|
"button_create": "Create",
|
||||||
"permission_join": "Join ({val})",
|
"permission_join": "Join ({val})",
|
||||||
"permission_read": "Read ({val})",
|
"permission_read": "Read ({val})",
|
||||||
"permission_write": "Write ({val})",
|
"permission_write": "Write ({val})",
|
||||||
|
|||||||
+18
-1
@@ -100,5 +100,22 @@
|
|||||||
"menu_item_unblock": "Разблокировать",
|
"menu_item_unblock": "Разблокировать",
|
||||||
"menu_item_block": "Заблокировать",
|
"menu_item_block": "Заблокировать",
|
||||||
"menu_item_member_delete": "Отписать",
|
"menu_item_member_delete": "Отписать",
|
||||||
"title_info": "Подробности"
|
"title_info": "Подробности",
|
||||||
|
"new_password_placeholder": "Введите новый пароль",
|
||||||
|
"label_reset_password": "Отправить емейл для смены пароля:",
|
||||||
|
"credential_email_prompt": "Регистрационный емейл",
|
||||||
|
"button_reset": "Изменить",
|
||||||
|
"button_send_request": "Отправить",
|
||||||
|
"action_cancel": "отменить",
|
||||||
|
"upload_finishing": "завершение...",
|
||||||
|
"no_contacts": "Ничего нет :-(",
|
||||||
|
"contacts_not_found_short": "Нет контактов для запроса '{query}'",
|
||||||
|
"title_all_contacts": "Все контакты",
|
||||||
|
"error_invalid_id": "Неверный ID",
|
||||||
|
"group_user_id_prompt": "ID чата или пользователя",
|
||||||
|
"button_subscribe": "Подписаться",
|
||||||
|
"topic_name_editing_placeholder": "Название чата",
|
||||||
|
"button_create": "Создать",
|
||||||
|
"badge_you": "вы",
|
||||||
|
"badge_owner": "влад."
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ const messages =
|
|||||||
allMessages.en;
|
allMessages.en;
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<IntlProvider locale={language} messages={messages} >
|
<IntlProvider locale={language} messages={messages} textComponent={React.Fragment}>
|
||||||
<TinodeWeb />
|
<TinodeWeb />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
document.getElementById('mountPoint')
|
document.getElementById('mountPoint')
|
||||||
|
|||||||
+37
-3
@@ -49,6 +49,11 @@
|
|||||||
"tabtitle_new_group": "new group",
|
"tabtitle_new_group": "new group",
|
||||||
"tabtitle_group_by_id": "by id",
|
"tabtitle_group_by_id": "by id",
|
||||||
"search_for_contacts": "Use search to find contacts",
|
"search_for_contacts": "Use search to find contacts",
|
||||||
|
"new_password_placeholder": "Enter new password",
|
||||||
|
"label_reset_password": "Send a password reset email:",
|
||||||
|
"credential_email_prompt": "Your registration email",
|
||||||
|
"button_reset": "Reset",
|
||||||
|
"button_send_request": "Send request",
|
||||||
"label_server_to_use": "Server to use:",
|
"label_server_to_use": "Server to use:",
|
||||||
"label_wire_transport": "Wire transport:",
|
"label_wire_transport": "Wire transport:",
|
||||||
"button_update": "Update",
|
"button_update": "Update",
|
||||||
@@ -65,6 +70,8 @@
|
|||||||
"numeric_confirmation_code_prompt": "Numbers only",
|
"numeric_confirmation_code_prompt": "Numbers only",
|
||||||
"button_confirm": "Confirm",
|
"button_confirm": "Confirm",
|
||||||
"invalid_content": "invalid content",
|
"invalid_content": "invalid content",
|
||||||
|
"badge_you": "you",
|
||||||
|
"badge_owner": "owner",
|
||||||
"menu_item_info": "Info",
|
"menu_item_info": "Info",
|
||||||
"menu_item_clear_messages": "Clear messages",
|
"menu_item_clear_messages": "Clear messages",
|
||||||
"menu_item_clear_messages_for_all": "Clear for All",
|
"menu_item_clear_messages_for_all": "Clear for All",
|
||||||
@@ -76,13 +83,23 @@
|
|||||||
"menu_item_unblock": "Unblock",
|
"menu_item_unblock": "Unblock",
|
||||||
"menu_item_block": "Block",
|
"menu_item_block": "Block",
|
||||||
"menu_item_member_delete": "Remove",
|
"menu_item_member_delete": "Remove",
|
||||||
"title_group_members": "Group members",
|
"action_cancel": "cancel",
|
||||||
|
"upload_finishing": "finishing...",
|
||||||
|
"no_contacts": "You have no contacts :-(",
|
||||||
|
"contacts_not_found_short": "No contacts match '{query}'",
|
||||||
|
"title_group_members": "Group Members",
|
||||||
|
"title_all_contacts": "All Contacts",
|
||||||
"button_ok": "OK",
|
"button_ok": "OK",
|
||||||
"button_cancel": "Cancel",
|
"button_cancel": "Cancel",
|
||||||
"download_action": "download",
|
"download_action": "download",
|
||||||
"label_file_name": "File name:",
|
"label_file_name": "File name:",
|
||||||
"label_content_type": "Content type:",
|
"label_content_type": "Content type:",
|
||||||
"label_size": "Size:",
|
"label_size": "Size:",
|
||||||
|
"error_invalid_id": "Invalid ID",
|
||||||
|
"group_user_id_prompt": "Group or User ID",
|
||||||
|
"button_subscribe": "Subscribe",
|
||||||
|
"topic_name_editing_placeholder": "Freeform name of the group",
|
||||||
|
"button_create": "Create",
|
||||||
"permission_join": "Join ({val})",
|
"permission_join": "Join ({val})",
|
||||||
"permission_read": "Read ({val})",
|
"permission_read": "Read ({val})",
|
||||||
"permission_write": "Write ({val})",
|
"permission_write": "Write ({val})",
|
||||||
@@ -167,7 +184,7 @@
|
|||||||
"email_dative": "емейлу",
|
"email_dative": "емейлу",
|
||||||
"title_group_members": "Участники",
|
"title_group_members": "Участники",
|
||||||
"download_action": "скачать",
|
"download_action": "скачать",
|
||||||
"permission_join": "Присоединяться ({val})",
|
"permission_join": "Подписываться ({val})",
|
||||||
"permission_read": "Читать ({val})",
|
"permission_read": "Читать ({val})",
|
||||||
"permission_write": "Писать ({val})",
|
"permission_write": "Писать ({val})",
|
||||||
"permission_pres": "Уведомлять ({val})",
|
"permission_pres": "Уведомлять ({val})",
|
||||||
@@ -205,6 +222,23 @@
|
|||||||
"menu_item_unblock": "Разблокировать",
|
"menu_item_unblock": "Разблокировать",
|
||||||
"menu_item_block": "Заблокировать",
|
"menu_item_block": "Заблокировать",
|
||||||
"menu_item_member_delete": "Отписать",
|
"menu_item_member_delete": "Отписать",
|
||||||
"title_info": "Подробности"
|
"title_info": "Подробности",
|
||||||
|
"new_password_placeholder": "Введите новый пароль",
|
||||||
|
"label_reset_password": "Отправить емейл для смены пароля:",
|
||||||
|
"credential_email_prompt": "Регистрационный емейл",
|
||||||
|
"button_reset": "Изменить",
|
||||||
|
"button_send_request": "Отправить",
|
||||||
|
"action_cancel": "отменить",
|
||||||
|
"upload_finishing": "завершение...",
|
||||||
|
"no_contacts": "Ничего нет :-(",
|
||||||
|
"contacts_not_found_short": "Нет контактов для запроса '{query}'",
|
||||||
|
"title_all_contacts": "Все контакты",
|
||||||
|
"error_invalid_id": "Неверный ID",
|
||||||
|
"group_user_id_prompt": "ID чата или пользователя",
|
||||||
|
"button_subscribe": "Подписаться",
|
||||||
|
"topic_name_editing_placeholder": "Название чата",
|
||||||
|
"button_create": "Создать",
|
||||||
|
"badge_you": "вы",
|
||||||
|
"badge_owner": "влад."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import Tinode from 'tinode-sdk';
|
||||||
|
|
||||||
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
||||||
import CheckBox from '../widgets/checkbox.jsx';
|
import CheckBox from '../widgets/checkbox.jsx';
|
||||||
import ContactList from '../widgets/contact-list.jsx';
|
import ContactList from '../widgets/contact-list.jsx';
|
||||||
@@ -225,7 +227,7 @@ class InfoView extends React.Component {
|
|||||||
this.setState({private: priv});
|
this.setState({private: priv});
|
||||||
this.props.onTopicDescUpdate(this.props.topic,
|
this.props.onTopicDescUpdate(this.props.topic,
|
||||||
null,
|
null,
|
||||||
priv);
|
priv || Tinode.DEL_CHAR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
/* Create new topic and invite users or send an invite */
|
// Create new topic and invite users or send an invite.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// A password reset form.
|
// A password reset form.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import VisiblePassword from '../widgets/visible-password.jsx';
|
import VisiblePassword from '../widgets/visible-password.jsx';
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ export default class PasswordResetView extends React.PureComponent {
|
|||||||
if (this.state.token) {
|
if (this.state.token) {
|
||||||
this.props.onReset(this.state.scheme, this.state.password.trim(), this.state.token);
|
this.props.onReset(this.state.scheme, this.state.password.trim(), this.state.token);
|
||||||
} else {
|
} else {
|
||||||
this.props.onRequest("email", this.state.email.trim());
|
this.props.onRequest('email', this.state.email.trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,25 +47,39 @@ export default class PasswordResetView extends React.PureComponent {
|
|||||||
return (
|
return (
|
||||||
<form id="password-reset-form" onSubmit={this.handleSubmit}>
|
<form id="password-reset-form" onSubmit={this.handleSubmit}>
|
||||||
{reset ?
|
{reset ?
|
||||||
<VisiblePassword
|
<FormattedMessage id="new_password_placeholder" defaultMessage="Enter new password"
|
||||||
placeholder="Enter new password"
|
description="Placeholder for entering new password">{
|
||||||
autoComplete="new-password"
|
(placeholder) => <VisiblePassword
|
||||||
value={this.state.password}
|
placeholder={placeholder}
|
||||||
required={true} autoFocus={true}
|
autoComplete="new-password"
|
||||||
onChange={this.handlePasswordChange} />
|
value={this.state.password}
|
||||||
|
required={true} autoFocus={true}
|
||||||
|
onChange={this.handlePasswordChange} />
|
||||||
|
}</FormattedMessage>
|
||||||
:
|
:
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<label htmlFor="inputEmail">Send a password reset email:</label>
|
<label htmlFor="inputEmail">
|
||||||
<input type="email" id="inputEmail"
|
<FormattedMessage id="label_reset_password"
|
||||||
placeholder="Your registration email"
|
defaultMessage="Send a password reset email:"
|
||||||
autoComplete="email"
|
description="Label for password reset field" />
|
||||||
value={this.state.email}
|
</label>
|
||||||
onChange={this.handleEmailChange}
|
<FormattedMessage id="credential_email_prompt" defaultMessage="Your registration email"
|
||||||
required autoFocus />
|
description="Placeholder for entering email">{
|
||||||
|
(placeholder) => <input type="email" id="inputEmail"
|
||||||
|
placeholder={placeholder}
|
||||||
|
autoComplete="email"
|
||||||
|
value={this.state.email}
|
||||||
|
onChange={this.handleEmailChange}
|
||||||
|
required autoFocus />
|
||||||
|
}</FormattedMessage>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
<div className="dialog-buttons">
|
<div className="dialog-buttons">
|
||||||
<button className="blue" type="submit">{reset ? "Reset" : "Send request"}</button>
|
<button className="blue" type="submit">{reset ?
|
||||||
|
<FormattedMessage id="button_reset" defaultMessage="Reset" description="Button [Reset]" /> :
|
||||||
|
<FormattedMessage id="button_send_request" defaultMessage="Send request"
|
||||||
|
description="Button [Send request]" />
|
||||||
|
}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,17 +2,16 @@ import React from 'react';
|
|||||||
|
|
||||||
/* Contact's labels: [you], [muted], [blocked], etc */
|
/* Contact's labels: [you], [muted], [blocked], etc */
|
||||||
// FIXME: this class is unused.
|
// FIXME: this class is unused.
|
||||||
export default class ContactBadges_UNUSED_REMOVE extends React.PureComponent {
|
export default class ContactBadges extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
let badges = null;
|
let badges = null;
|
||||||
if (this.props.badges && this.props.badges.length > 0) {
|
if (this.props.badges && this.props.badges.length > 0) {
|
||||||
badges = [];
|
badges = [];
|
||||||
this.props.badges.map(function(b) {
|
this.props.badges.map(function(b) {
|
||||||
var style = 'badge' + (b.color ? ' ' + b.color : '');
|
let style = 'badge' + (b.color ? ' ' + b.color : '');
|
||||||
// Badge names are expected to be unique, so using the name as the key.
|
badges.push(<span className={style} key={b.key || b.name}>{b.name}</span>);
|
||||||
badges.push(<span className={style} key={b.name}>{b.name}</span>);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return badges;
|
return <span>{badges}</span>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,26 @@
|
|||||||
|
// ContactList: component for showing a list of contacts,
|
||||||
|
// such as a list of group members in a group chat.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
import Contact from './contact.jsx';
|
import Contact from './contact.jsx';
|
||||||
|
|
||||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||||
|
|
||||||
/* ContactList: component for showing a list of contacts,
|
const messages = defineMessages({
|
||||||
* such as a list of group members in a group chat */
|
badge_you: {
|
||||||
export default class ContactList extends React.Component {
|
id: 'badge_you',
|
||||||
|
defaultMessage: 'you',
|
||||||
|
description: 'Badge for indicating the current user'
|
||||||
|
},
|
||||||
|
badge_owner: {
|
||||||
|
id: 'badge_owner',
|
||||||
|
defaultMessage: 'owner',
|
||||||
|
description: 'Badge for indicating the owner'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class ContactList extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
var contactNodes = [];
|
var contactNodes = [];
|
||||||
var showCheckmark = Array.isArray(this.props.topicSelected);
|
var showCheckmark = Array.isArray(this.props.topicSelected);
|
||||||
@@ -34,14 +48,14 @@ export default class ContactList extends React.Component {
|
|||||||
var badges = [];
|
var badges = [];
|
||||||
if (this.props.showMode) {
|
if (this.props.showMode) {
|
||||||
if (key === this.props.myUserId) {
|
if (key === this.props.myUserId) {
|
||||||
badges.push({name: "you", color: 'green'});
|
badges.push({name: formatMessage(messages.badge_you), color: 'green'});
|
||||||
}
|
}
|
||||||
if (c.acs && c.acs.isOwner()) {
|
if (c.acs && c.acs.isOwner()) {
|
||||||
badges.push({name: "owner"});
|
badges.push({name: formatMessage(messages.badge_owner), color: 'blue'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var comment = Array.isArray(c.private) ?
|
var comment = Array.isArray(c.private) ?
|
||||||
c.private.join(', ') : (c.private ? c.private.comment : null);
|
c.private.join(',') : (c.private ? c.private.comment : null);
|
||||||
|
|
||||||
contactNodes.push(
|
contactNodes.push(
|
||||||
<Contact
|
<Contact
|
||||||
@@ -79,4 +93,5 @@ export default class ContactList extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/* END ContactList */
|
|
||||||
|
export default injectIntl(ContactList);
|
||||||
|
|||||||
+4
-11
@@ -3,6 +3,7 @@ import React from 'react';
|
|||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import LetterTile from './letter-tile.jsx';
|
import LetterTile from './letter-tile.jsx';
|
||||||
|
import ContactBadges from './contact-badges.jsx';
|
||||||
import UnreadBadge from './unread-badge.jsx';
|
import UnreadBadge from './unread-badge.jsx';
|
||||||
|
|
||||||
export default class Contact extends React.Component {
|
export default class Contact extends React.Component {
|
||||||
@@ -37,17 +38,9 @@ export default class Contact extends React.Component {
|
|||||||
}
|
}
|
||||||
let online = this.props.now ? 'online' : 'offline';
|
let online = this.props.now ? 'online' : 'offline';
|
||||||
let avatar = this.props.avatar ? this.props.avatar : true;
|
let avatar = this.props.avatar ? this.props.avatar : true;
|
||||||
let badges = [];
|
let badges = this.props.badges.slice();
|
||||||
if (this.props.badges && this.props.badges.length > 0) {
|
|
||||||
let count = 0;
|
|
||||||
this.props.badges.map(function(b) {
|
|
||||||
let style = 'badge' + (b.color ? ' ' + b.color : '');
|
|
||||||
badges.push(<span className={style} key={count}>{b.name}</span>);
|
|
||||||
count ++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (this.props.showMode && this.props.acs) {
|
if (this.props.showMode && this.props.acs) {
|
||||||
badges.push(<span className="badge" key="mode">{this.props.acs.getMode()}</span>);
|
badges.push({name: this.props.acs.getMode(), key: 'mode'});
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -68,7 +61,7 @@ export default class Contact extends React.Component {
|
|||||||
{this.props.unread > 0 ? <UnreadBadge count={this.props.unread} /> : null}
|
{this.props.unread > 0 ? <UnreadBadge count={this.props.unread} /> : null}
|
||||||
</div>
|
</div>
|
||||||
{this.props.comment ? <div className="contact-comment">{this.props.comment}</div> : null}
|
{this.props.comment ? <div className="contact-comment">{this.props.comment}</div> : null}
|
||||||
<span>{badges}</span>
|
<ContactBadges badges={badges} />
|
||||||
</div>
|
</div>
|
||||||
{this.props.showContextMenu ?
|
{this.props.showContextMenu ?
|
||||||
<span className="menuTrigger">
|
<span className="menuTrigger">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
// File uload/download progress indicator with a cancel inside.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
/* File uload/download progress indicator with a cancel inside */
|
|
||||||
|
|
||||||
export default class FileProgress extends React.PureComponent {
|
export default class FileProgress extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
@@ -8,9 +8,13 @@ export default class FileProgress extends React.PureComponent {
|
|||||||
<div className="uploader">
|
<div className="uploader">
|
||||||
<div><span style={{width: (this.props.progress * 100) + "%"}}></span></div>
|
<div><span style={{width: (this.props.progress * 100) + "%"}}></span></div>
|
||||||
{this.props.progress < 0.999 ?
|
{this.props.progress < 0.999 ?
|
||||||
<a href="javascript:;" onClick={this.props.onCancel}><i className="material-icons">close</i> cancel</a>
|
<a href="javascript:;" onClick={this.props.onCancel}>
|
||||||
|
<i className="material-icons">close</i> <FormattedMessage id="action_cancel"
|
||||||
|
defaultMessage="cancel" description="Call to action [cancel]" />
|
||||||
|
</a>
|
||||||
:
|
:
|
||||||
<span>finishing...</span>
|
<FormattedMessage id="upload_finishing" defaultMessage="finishing..."
|
||||||
|
description="Notification that upload is finishing" />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,19 @@ import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
|||||||
import ChipInput from './chip-input.jsx';
|
import ChipInput from './chip-input.jsx';
|
||||||
import ContactList from './contact-list.jsx';
|
import ContactList from './contact-list.jsx';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
no_contacts: {
|
||||||
|
id: 'no_contacts',
|
||||||
|
defaultMessage: 'You have no contacts :-(',
|
||||||
|
description: 'Shown in ContactsView when the user has no contacts'
|
||||||
|
},
|
||||||
|
contacts_not_found: {
|
||||||
|
id: 'contacts_not_found_short',
|
||||||
|
defaultMessage: "No contacts match '{query}'",
|
||||||
|
description: 'Shown in ContactsView when search returned no results'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
class GroupManager extends React.Component {
|
class GroupManager extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -13,7 +26,7 @@ class GroupManager extends React.Component {
|
|||||||
members: props.members,
|
members: props.members,
|
||||||
index: GroupManager.indexMembers(props.members),
|
index: GroupManager.indexMembers(props.members),
|
||||||
contactFilter: '',
|
contactFilter: '',
|
||||||
noContactsMessage: "You have no contacts :-(",
|
noContactsMessage: props.intl.formatMessage(messages.no_contacts),
|
||||||
selectedContacts: GroupManager.selectedContacts(props.members)
|
selectedContacts: GroupManager.selectedContacts(props.members)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,8 +99,8 @@ class GroupManager extends React.Component {
|
|||||||
handleContactFilter(val) {
|
handleContactFilter(val) {
|
||||||
const {formatMessage} = this.props.intl;
|
const {formatMessage} = this.props.intl;
|
||||||
const msg = !val ?
|
const msg = !val ?
|
||||||
"You have no contacts :-(" :
|
formatMessage(messages.no_contacts) :
|
||||||
"No contacts match '" + val + "'";
|
formatMessage(messages.contacts_not_found, {query: val});
|
||||||
|
|
||||||
this.setState({contactFilter: val, noContactsMessage: msg});
|
this.setState({contactFilter: val, noContactsMessage: msg});
|
||||||
}
|
}
|
||||||
@@ -135,7 +148,7 @@ class GroupManager extends React.Component {
|
|||||||
<div id="group-manager">
|
<div id="group-manager">
|
||||||
<div className="panel-form-row">
|
<div className="panel-form-row">
|
||||||
<label className="small">
|
<label className="small">
|
||||||
<FormattedMessage id="title_group_members" defaultMessage="Group members" description="Section title" />
|
<FormattedMessage id="title_group_members" defaultMessage="Group Members" description="Section title" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="panel-form-row">
|
<div className="panel-form-row">
|
||||||
@@ -147,7 +160,10 @@ class GroupManager extends React.Component {
|
|||||||
onChipRemoved={this.handleMemberRemoved} />
|
onChipRemoved={this.handleMemberRemoved} />
|
||||||
</div>
|
</div>
|
||||||
<div className="panel-form-row">
|
<div className="panel-form-row">
|
||||||
<label className="small">All contacts</label>
|
<label className="small">
|
||||||
|
<FormattedMessage id="title_all_contacts" defaultMessage="All Contacts"
|
||||||
|
description="Section title [All Contacts]" />
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<ContactList
|
<ContactList
|
||||||
contacts={this.props.contacts}
|
contacts={this.props.contacts}
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
export default class NewTopicById extends React.PureComponent {
|
const messages = defineMessages({
|
||||||
|
invalid_id: {
|
||||||
|
id: 'error_invalid_id',
|
||||||
|
defaultMessage: 'Invalid ID',
|
||||||
|
description: 'Error message'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class NewTopicById extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -30,7 +39,7 @@ export default class NewTopicById extends React.PureComponent {
|
|||||||
if (name.length > 3 && (name.substr(0, 3) == 'usr' || name.substr(0, 3) == 'grp')) {
|
if (name.length > 3 && (name.substr(0, 3) == 'usr' || name.substr(0, 3) == 'grp')) {
|
||||||
this.props.onSubmit(name);
|
this.props.onSubmit(name);
|
||||||
} else {
|
} else {
|
||||||
this.props.onError("Invalid ID", 'err');
|
this.props.onError(this.props.intl.formatMessage(messages.invalid_id), 'err');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,14 +48,22 @@ export default class NewTopicById extends React.PureComponent {
|
|||||||
return (
|
return (
|
||||||
<div className="panel-form">
|
<div className="panel-form">
|
||||||
<div className="panel-form-row">
|
<div className="panel-form-row">
|
||||||
<input type="text" placeholder="Group or User ID"
|
<FormattedMessage id="group_user_id_prompt" defaultMessage="Group or User ID"
|
||||||
value={this.state.groupId} onChange={this.handleChange}
|
description="Prompt for entering user or group ID">{
|
||||||
onKeyPress={this.handleKeyPress} required />
|
(prompt) => <input type="text" placeholder={prompt}
|
||||||
|
value={this.state.groupId} onChange={this.handleChange}
|
||||||
|
onKeyPress={this.handleKeyPress} required />
|
||||||
|
}</FormattedMessage>
|
||||||
</div>
|
</div>
|
||||||
<div className="dialog-buttons">
|
<div className="dialog-buttons">
|
||||||
<button className="blue" onClick={this.handleSubmit}>Subscribe</button>
|
<button className="blue" onClick={this.handleSubmit}>
|
||||||
|
<FormattedMessage id="button_subscribe" defaultMessage="Subscribe"
|
||||||
|
description="Button [Subscribe]" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default injectIntl(NewTopicById);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import AvatarUpload from './avatar-upload.jsx';
|
import AvatarUpload from './avatar-upload.jsx';
|
||||||
import TagManager from './tag-manager.jsx';
|
import TagManager from './tag-manager.jsx';
|
||||||
@@ -56,25 +57,39 @@ export default class NewTopicGroup extends React.PureComponent {
|
|||||||
<form className="panel-form" onSubmit={this.handleSubmit}>
|
<form className="panel-form" onSubmit={this.handleSubmit}>
|
||||||
<div className="panel-form-row">
|
<div className="panel-form-row">
|
||||||
<div className="panel-form-column">
|
<div className="panel-form-column">
|
||||||
<label className="small" htmlFor="new-topic-fn">Group name</label>
|
<label className="small" htmlFor="new-topic-fn">
|
||||||
<input type="text" id="new-topic-fn" placeholder="Freeform name of the group"
|
<FormattedMessage id="label_topic_name" />
|
||||||
value={this.state.fn} onChange={this.handleFnChange} autoFocus required />
|
</label>
|
||||||
|
<FormattedMessage id="topic_name_editing_placeholder" defaultMessage="Freeform name of the group"
|
||||||
|
description="Prompt for entering topic name">{
|
||||||
|
(placeholder) => <input type="text" id="new-topic-fn" placeholder={placeholder}
|
||||||
|
value={this.state.fn} onChange={this.handleFnChange} autoFocus required />
|
||||||
|
}</FormattedMessage>
|
||||||
<br />
|
<br />
|
||||||
<label className="small" htmlFor="new-topic-priv">Private comment</label>
|
<label className="small" htmlFor="new-topic-priv">
|
||||||
<input type="text" id="new-topic-priv" placeholder="Visible to you only"
|
<FormattedMessage id="label_private" />
|
||||||
value={this.state.private} onChange={this.handlePrivateChange} />
|
</label>
|
||||||
|
<FormattedMessage id="private_editing_placeholder">{
|
||||||
|
(placeholder) => <input type="text" id="new-topic-priv" placeholder={placeholder}
|
||||||
|
value={this.state.private} onChange={this.handlePrivateChange} />
|
||||||
|
}</FormattedMessage>
|
||||||
</div>
|
</div>
|
||||||
<AvatarUpload
|
<AvatarUpload
|
||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
onImageChanged={this.handleImageChanged} />
|
onImageChanged={this.handleImageChanged} />
|
||||||
</div>
|
</div>
|
||||||
<TagManager
|
<FormattedMessage id="title_tag_manager">{
|
||||||
tags={this.state.tags}
|
(title) => <TagManager
|
||||||
activated={true}
|
tags={this.state.tags}
|
||||||
onTagsChanged={this.handleTagsChanged}
|
activated={true}
|
||||||
title="Optional tags (search and discovery)" />
|
onTagsChanged={this.handleTagsChanged}
|
||||||
|
title={title} />
|
||||||
|
}</FormattedMessage>
|
||||||
<div className="dialog-buttons">
|
<div className="dialog-buttons">
|
||||||
<button className={submitClasses}>Create</button>
|
<button className={submitClasses}>
|
||||||
|
<FormattedMessage id="button_create" defaultMessage="Create"
|
||||||
|
description="Button [Create]" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl';
|
|||||||
|
|
||||||
import ChipInput from './chip-input.jsx';
|
import ChipInput from './chip-input.jsx';
|
||||||
|
|
||||||
|
import { MIN_TAG_LENGTH } from '../config.js';
|
||||||
import { arrayEqual } from '../lib/utils.js';
|
import { arrayEqual } from '../lib/utils.js';
|
||||||
|
|
||||||
export default class TagManager extends React.Component {
|
export default class TagManager extends React.Component {
|
||||||
|
|||||||
+23
-11
File diff suppressed because one or more lines are too long
+4
-4
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user