all components are translated now
This commit is contained in:
@@ -1448,12 +1448,24 @@ ul.tabbar li.active > a:after {
|
||||
color: #660;
|
||||
}
|
||||
|
||||
.badge.blue {
|
||||
border-color: #339;
|
||||
background-color: #eef;
|
||||
color: #339;
|
||||
}
|
||||
|
||||
.badge.red {
|
||||
border-color: #933;
|
||||
background-color: #fee;
|
||||
color: #933;
|
||||
}
|
||||
|
||||
.badge.magenta {
|
||||
border-color: #939;
|
||||
background-color: #fef;
|
||||
color: #939;
|
||||
}
|
||||
|
||||
/* Letter tile base style, responsive square box */
|
||||
.lettertile {
|
||||
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);
|
||||
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.
|
||||
// Mark missing or obsolete messages as such in translation files.
|
||||
@@ -64,7 +64,7 @@ globSync(LANG_PATTERN)
|
||||
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.
|
||||
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_group_by_id": "by id",
|
||||
"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_wire_transport": "Wire transport:",
|
||||
"button_update": "Update",
|
||||
@@ -64,6 +69,8 @@
|
||||
"numeric_confirmation_code_prompt": "Numbers only",
|
||||
"button_confirm": "Confirm",
|
||||
"invalid_content": "invalid content",
|
||||
"badge_you": "you",
|
||||
"badge_owner": "owner",
|
||||
"menu_item_info": "Info",
|
||||
"menu_item_clear_messages": "Clear messages",
|
||||
"menu_item_clear_messages_for_all": "Clear for All",
|
||||
@@ -75,13 +82,23 @@
|
||||
"menu_item_unblock": "Unblock",
|
||||
"menu_item_block": "Block",
|
||||
"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_cancel": "Cancel",
|
||||
"download_action": "download",
|
||||
"label_file_name": "File name:",
|
||||
"label_content_type": "Content type:",
|
||||
"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_read": "Read ({val})",
|
||||
"permission_write": "Write ({val})",
|
||||
|
||||
+18
-1
@@ -100,5 +100,22 @@
|
||||
"menu_item_unblock": "Разблокировать",
|
||||
"menu_item_block": "Заблокировать",
|
||||
"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;
|
||||
|
||||
ReactDOM.render(
|
||||
<IntlProvider locale={language} messages={messages} >
|
||||
<IntlProvider locale={language} messages={messages} textComponent={React.Fragment}>
|
||||
<TinodeWeb />
|
||||
</IntlProvider>,
|
||||
document.getElementById('mountPoint')
|
||||
|
||||
+37
-3
@@ -49,6 +49,11 @@
|
||||
"tabtitle_new_group": "new group",
|
||||
"tabtitle_group_by_id": "by id",
|
||||
"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_wire_transport": "Wire transport:",
|
||||
"button_update": "Update",
|
||||
@@ -65,6 +70,8 @@
|
||||
"numeric_confirmation_code_prompt": "Numbers only",
|
||||
"button_confirm": "Confirm",
|
||||
"invalid_content": "invalid content",
|
||||
"badge_you": "you",
|
||||
"badge_owner": "owner",
|
||||
"menu_item_info": "Info",
|
||||
"menu_item_clear_messages": "Clear messages",
|
||||
"menu_item_clear_messages_for_all": "Clear for All",
|
||||
@@ -76,13 +83,23 @@
|
||||
"menu_item_unblock": "Unblock",
|
||||
"menu_item_block": "Block",
|
||||
"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_cancel": "Cancel",
|
||||
"download_action": "download",
|
||||
"label_file_name": "File name:",
|
||||
"label_content_type": "Content type:",
|
||||
"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_read": "Read ({val})",
|
||||
"permission_write": "Write ({val})",
|
||||
@@ -167,7 +184,7 @@
|
||||
"email_dative": "емейлу",
|
||||
"title_group_members": "Участники",
|
||||
"download_action": "скачать",
|
||||
"permission_join": "Присоединяться ({val})",
|
||||
"permission_join": "Подписываться ({val})",
|
||||
"permission_read": "Читать ({val})",
|
||||
"permission_write": "Писать ({val})",
|
||||
"permission_pres": "Уведомлять ({val})",
|
||||
@@ -205,6 +222,23 @@
|
||||
"menu_item_unblock": "Разблокировать",
|
||||
"menu_item_block": "Заблокировать",
|
||||
"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 { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import Tinode from 'tinode-sdk';
|
||||
|
||||
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
||||
import CheckBox from '../widgets/checkbox.jsx';
|
||||
import ContactList from '../widgets/contact-list.jsx';
|
||||
@@ -225,7 +227,7 @@ class InfoView extends React.Component {
|
||||
this.setState({private: priv});
|
||||
this.props.onTopicDescUpdate(this.props.topic,
|
||||
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 { FormattedMessage } from 'react-intl';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// A password reset form.
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import VisiblePassword from '../widgets/visible-password.jsx';
|
||||
|
||||
@@ -29,7 +30,7 @@ export default class PasswordResetView extends React.PureComponent {
|
||||
if (this.state.token) {
|
||||
this.props.onReset(this.state.scheme, this.state.password.trim(), this.state.token);
|
||||
} 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 (
|
||||
<form id="password-reset-form" onSubmit={this.handleSubmit}>
|
||||
{reset ?
|
||||
<VisiblePassword
|
||||
placeholder="Enter new password"
|
||||
autoComplete="new-password"
|
||||
value={this.state.password}
|
||||
required={true} autoFocus={true}
|
||||
onChange={this.handlePasswordChange} />
|
||||
<FormattedMessage id="new_password_placeholder" defaultMessage="Enter new password"
|
||||
description="Placeholder for entering new password">{
|
||||
(placeholder) => <VisiblePassword
|
||||
placeholder={placeholder}
|
||||
autoComplete="new-password"
|
||||
value={this.state.password}
|
||||
required={true} autoFocus={true}
|
||||
onChange={this.handlePasswordChange} />
|
||||
}</FormattedMessage>
|
||||
:
|
||||
<React.Fragment>
|
||||
<label htmlFor="inputEmail">Send a password reset email:</label>
|
||||
<input type="email" id="inputEmail"
|
||||
placeholder="Your registration email"
|
||||
autoComplete="email"
|
||||
value={this.state.email}
|
||||
onChange={this.handleEmailChange}
|
||||
required autoFocus />
|
||||
<label htmlFor="inputEmail">
|
||||
<FormattedMessage id="label_reset_password"
|
||||
defaultMessage="Send a password reset email:"
|
||||
description="Label for password reset field" />
|
||||
</label>
|
||||
<FormattedMessage id="credential_email_prompt" defaultMessage="Your registration email"
|
||||
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>
|
||||
}
|
||||
<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>
|
||||
</form>
|
||||
);
|
||||
|
||||
@@ -2,17 +2,16 @@ import React from 'react';
|
||||
|
||||
/* Contact's labels: [you], [muted], [blocked], etc */
|
||||
// FIXME: this class is unused.
|
||||
export default class ContactBadges_UNUSED_REMOVE extends React.PureComponent {
|
||||
export default class ContactBadges extends React.PureComponent {
|
||||
render() {
|
||||
let badges = null;
|
||||
if (this.props.badges && this.props.badges.length > 0) {
|
||||
badges = [];
|
||||
this.props.badges.map(function(b) {
|
||||
var 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.name}>{b.name}</span>);
|
||||
let style = 'badge' + (b.color ? ' ' + b.color : '');
|
||||
badges.push(<span className={style} key={b.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 { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import Contact from './contact.jsx';
|
||||
|
||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||
|
||||
/* ContactList: component for showing a list of contacts,
|
||||
* such as a list of group members in a group chat */
|
||||
export default class ContactList extends React.Component {
|
||||
const messages = defineMessages({
|
||||
badge_you: {
|
||||
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() {
|
||||
var contactNodes = [];
|
||||
var showCheckmark = Array.isArray(this.props.topicSelected);
|
||||
@@ -34,14 +48,14 @@ export default class ContactList extends React.Component {
|
||||
var badges = [];
|
||||
if (this.props.showMode) {
|
||||
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()) {
|
||||
badges.push({name: "owner"});
|
||||
badges.push({name: formatMessage(messages.badge_owner), color: 'blue'});
|
||||
}
|
||||
}
|
||||
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(
|
||||
<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 LetterTile from './letter-tile.jsx';
|
||||
import ContactBadges from './contact-badges.jsx';
|
||||
import UnreadBadge from './unread-badge.jsx';
|
||||
|
||||
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 avatar = this.props.avatar ? this.props.avatar : true;
|
||||
let badges = [];
|
||||
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 ++;
|
||||
});
|
||||
}
|
||||
let badges = this.props.badges.slice();
|
||||
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 (
|
||||
@@ -68,7 +61,7 @@ export default class Contact extends React.Component {
|
||||
{this.props.unread > 0 ? <UnreadBadge count={this.props.unread} /> : null}
|
||||
</div>
|
||||
{this.props.comment ? <div className="contact-comment">{this.props.comment}</div> : null}
|
||||
<span>{badges}</span>
|
||||
<ContactBadges badges={badges} />
|
||||
</div>
|
||||
{this.props.showContextMenu ?
|
||||
<span className="menuTrigger">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// File uload/download progress indicator with a cancel inside.
|
||||
import React from 'react';
|
||||
|
||||
/* File uload/download progress indicator with a cancel inside */
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export default class FileProgress extends React.PureComponent {
|
||||
render() {
|
||||
@@ -8,9 +8,13 @@ export default class FileProgress extends React.PureComponent {
|
||||
<div className="uploader">
|
||||
<div><span style={{width: (this.props.progress * 100) + "%"}}></span></div>
|
||||
{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>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,19 @@ import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
import ChipInput from './chip-input.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 {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -13,7 +26,7 @@ class GroupManager extends React.Component {
|
||||
members: props.members,
|
||||
index: GroupManager.indexMembers(props.members),
|
||||
contactFilter: '',
|
||||
noContactsMessage: "You have no contacts :-(",
|
||||
noContactsMessage: props.intl.formatMessage(messages.no_contacts),
|
||||
selectedContacts: GroupManager.selectedContacts(props.members)
|
||||
};
|
||||
|
||||
@@ -86,8 +99,8 @@ class GroupManager extends React.Component {
|
||||
handleContactFilter(val) {
|
||||
const {formatMessage} = this.props.intl;
|
||||
const msg = !val ?
|
||||
"You have no contacts :-(" :
|
||||
"No contacts match '" + val + "'";
|
||||
formatMessage(messages.no_contacts) :
|
||||
formatMessage(messages.contacts_not_found, {query: val});
|
||||
|
||||
this.setState({contactFilter: val, noContactsMessage: msg});
|
||||
}
|
||||
@@ -135,7 +148,7 @@ class GroupManager extends React.Component {
|
||||
<div id="group-manager">
|
||||
<div className="panel-form-row">
|
||||
<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>
|
||||
</div>
|
||||
<div className="panel-form-row">
|
||||
@@ -147,7 +160,10 @@ class GroupManager extends React.Component {
|
||||
onChipRemoved={this.handleMemberRemoved} />
|
||||
</div>
|
||||
<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>
|
||||
<ContactList
|
||||
contacts={this.props.contacts}
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
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) {
|
||||
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')) {
|
||||
this.props.onSubmit(name);
|
||||
} 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 (
|
||||
<div className="panel-form">
|
||||
<div className="panel-form-row">
|
||||
<input type="text" placeholder="Group or User ID"
|
||||
value={this.state.groupId} onChange={this.handleChange}
|
||||
onKeyPress={this.handleKeyPress} required />
|
||||
<FormattedMessage id="group_user_id_prompt" defaultMessage="Group or User ID"
|
||||
description="Prompt for entering user or group ID">{
|
||||
(prompt) => <input type="text" placeholder={prompt}
|
||||
value={this.state.groupId} onChange={this.handleChange}
|
||||
onKeyPress={this.handleKeyPress} required />
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default injectIntl(NewTopicById);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import AvatarUpload from './avatar-upload.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}>
|
||||
<div className="panel-form-row">
|
||||
<div className="panel-form-column">
|
||||
<label className="small" htmlFor="new-topic-fn">Group name</label>
|
||||
<input type="text" id="new-topic-fn" placeholder="Freeform name of the group"
|
||||
value={this.state.fn} onChange={this.handleFnChange} autoFocus required />
|
||||
<label className="small" htmlFor="new-topic-fn">
|
||||
<FormattedMessage id="label_topic_name" />
|
||||
</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 />
|
||||
<label className="small" htmlFor="new-topic-priv">Private comment</label>
|
||||
<input type="text" id="new-topic-priv" placeholder="Visible to you only"
|
||||
value={this.state.private} onChange={this.handlePrivateChange} />
|
||||
<label className="small" htmlFor="new-topic-priv">
|
||||
<FormattedMessage id="label_private" />
|
||||
</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>
|
||||
<AvatarUpload
|
||||
onError={this.props.onError}
|
||||
onImageChanged={this.handleImageChanged} />
|
||||
</div>
|
||||
<TagManager
|
||||
tags={this.state.tags}
|
||||
activated={true}
|
||||
onTagsChanged={this.handleTagsChanged}
|
||||
title="Optional tags (search and discovery)" />
|
||||
<FormattedMessage id="title_tag_manager">{
|
||||
(title) => <TagManager
|
||||
tags={this.state.tags}
|
||||
activated={true}
|
||||
onTagsChanged={this.handleTagsChanged}
|
||||
title={title} />
|
||||
}</FormattedMessage>
|
||||
<div className="dialog-buttons">
|
||||
<button className={submitClasses}>Create</button>
|
||||
<button className={submitClasses}>
|
||||
<FormattedMessage id="button_create" defaultMessage="Create"
|
||||
description="Button [Create]" />
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import ChipInput from './chip-input.jsx';
|
||||
|
||||
import { MIN_TAG_LENGTH } from '../config.js';
|
||||
import { arrayEqual } from '../lib/utils.js';
|
||||
|
||||
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