merging
Этот коммит содержится в:
@@ -22,6 +22,8 @@
|
||||
"React": false,
|
||||
"ReactDOM": false,
|
||||
"ReactBootstrap": false,
|
||||
"ReactIntl": false,
|
||||
"ReactIntlLocaleData": false,
|
||||
"Chart": false,
|
||||
"katex": false
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import Constants from '../../utils/constants.jsx';
|
||||
var Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class ResetPasswordModal extends React.Component {
|
||||
@@ -20,8 +21,8 @@ export default class ResetPasswordModal extends React.Component {
|
||||
e.preventDefault();
|
||||
var password = ReactDOM.findDOMNode(this.refs.password).value;
|
||||
|
||||
if (!password || password.length < 5) {
|
||||
this.setState({serverError: 'Please enter at least 5 characters.'});
|
||||
if (!password || password.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
this.setState({serverError: 'Please enter at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters.'});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
const Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class ChannelInfoModal extends React.Component {
|
||||
@@ -10,10 +11,13 @@ export default class ChannelInfoModal extends React.Component {
|
||||
channel = {
|
||||
display_name: 'No Channel Found',
|
||||
name: 'No Channel Found',
|
||||
purpose: 'No Channel Found',
|
||||
id: 'No Channel Found'
|
||||
};
|
||||
}
|
||||
|
||||
const channelURL = Utils.getShortenedTeamURL() + channel.name;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
show={this.props.show}
|
||||
@@ -28,13 +32,17 @@ export default class ChannelInfoModal extends React.Component {
|
||||
<div className='col-sm-9'>{channel.display_name}</div>
|
||||
</div>
|
||||
<div className='row form-group'>
|
||||
<div className='col-sm-3 info__label'>{'Channel Handle:'}</div>
|
||||
<div className='col-sm-9'>{channel.name}</div>
|
||||
<div className='col-sm-3 info__label'>{'Channel URL:'}</div>
|
||||
<div className='col-sm-9'>{channelURL}</div>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className='col-sm-3 info__label'>{'Channel ID:'}</div>
|
||||
<div className='col-sm-9'>{channel.id}</div>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className='col-sm-3 info__label'>{'Channel Purpose:'}</div>
|
||||
<div className='col-sm-9'>{channel.purpose}</div>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<button
|
||||
|
||||
@@ -129,7 +129,7 @@ export default class CreateComment extends React.Component {
|
||||
function handlePostError(err) {
|
||||
let state = {};
|
||||
|
||||
if (err.message === 'Invalid RootId parameter') {
|
||||
if (err.id === 'api.post.create_post.root_id.app_error') {
|
||||
PostStore.removePendingPost(post.channel_id, post.pending_post_id);
|
||||
|
||||
if ($('#post_deleted').length > 0) {
|
||||
|
||||
@@ -186,7 +186,7 @@ export default class CreatePost extends React.Component {
|
||||
(err) => {
|
||||
const state = {};
|
||||
|
||||
if (err.message === 'Invalid RootId parameter') {
|
||||
if (err.id === 'api.post.create_post.root_id.app_error') {
|
||||
if ($('#post_deleted').length > 0) {
|
||||
$('#post_deleted').modal('show');
|
||||
}
|
||||
|
||||
@@ -151,7 +151,11 @@ export default class FileUpload extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('paste', function handlePaste(e) {
|
||||
document.addEventListener('paste', (e) => {
|
||||
if (!e.clipboardData) {
|
||||
return;
|
||||
}
|
||||
|
||||
var textarea = $(inputDiv.parentNode.parentNode).find('.custom-textarea')[0];
|
||||
|
||||
if (textarea !== e.target && !$.contains(textarea, e.target)) {
|
||||
|
||||
@@ -7,6 +7,8 @@ import LoginLdap from './login_ldap.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
var FormattedMessage = ReactIntl.FormattedMessage;
|
||||
|
||||
export default class Login extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -86,7 +88,12 @@ export default class Login extends React.Component {
|
||||
if (emailSignup) {
|
||||
forgotPassword = (
|
||||
<div className='form-group'>
|
||||
<a href={'/' + teamName + '/reset_password'}>{'I forgot my password'}</a>
|
||||
<a href={'/' + teamName + '/reset_password'}>
|
||||
<FormattedMessage
|
||||
id='login.forgot_password'
|
||||
defaultMessage='I forgot my password'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -141,7 +148,13 @@ export default class Login extends React.Component {
|
||||
{ldapLogin}
|
||||
{userSignUp}
|
||||
<div className='form-group margin--extra form-group--small'>
|
||||
<span><a href='/find_team'>{'Find your other teams'}</a></span>
|
||||
<span>
|
||||
<a href='/find_team'>
|
||||
<FormattedMessage
|
||||
id='login.find_teams'
|
||||
defaultMessage='Find your other teams'
|
||||
/>
|
||||
</a></span>
|
||||
</div>
|
||||
{forgotPassword}
|
||||
{teamSignUp}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as client from '../utils/client.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
export default class PasswordResetForm extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -16,8 +17,8 @@ export default class PasswordResetForm extends React.Component {
|
||||
var state = {};
|
||||
|
||||
var password = ReactDOM.findDOMNode(this.refs.password).value.trim();
|
||||
if (!password || password.length < 5) {
|
||||
state.error = 'Please enter at least 5 characters.';
|
||||
if (!password || password.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
state.error = 'Please enter at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters.';
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -31,7 +32,7 @@ export default class PasswordResetForm extends React.Component {
|
||||
data.data = this.props.data;
|
||||
data.name = this.props.teamName;
|
||||
|
||||
client.resetPassword(data,
|
||||
Client.resetPassword(data,
|
||||
function resetSuccess() {
|
||||
this.setState({error: null, updateText: 'Your password has been updated successfully.'});
|
||||
}.bind(this),
|
||||
@@ -59,7 +60,7 @@ export default class PasswordResetForm extends React.Component {
|
||||
return (
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h3>Password Reset</h3>
|
||||
<h3>{'Password Reset'}</h3>
|
||||
<form onSubmit={this.handlePasswordReset}>
|
||||
<p>{'Enter a new password for your ' + this.props.teamDisplayName + ' ' + global.window.mm_config.SiteName + ' account.'}</p>
|
||||
<div className={formClass}>
|
||||
@@ -77,7 +78,7 @@ export default class PasswordResetForm extends React.Component {
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
Change my password
|
||||
{'Change my password'}
|
||||
</button>
|
||||
{updateText}
|
||||
</form>
|
||||
|
||||
@@ -57,7 +57,10 @@ export default class PostsView extends React.Component {
|
||||
this.setState({displayNameType: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'false')});
|
||||
}
|
||||
isAtBottom() {
|
||||
return ((this.refs.postlist.scrollHeight - this.refs.postlist.scrollTop) === this.refs.postlist.clientHeight);
|
||||
// consider the view to be at the bottom if it's within this many pixels of the bottom
|
||||
const atBottomMargin = 10;
|
||||
|
||||
return this.refs.postlist.clientHeight + this.refs.postlist.scrollTop >= this.refs.postlist.scrollHeight - atBottomMargin;
|
||||
}
|
||||
handleScroll() {
|
||||
// HACK FOR RHS -- REMOVE WHEN RHS DIES
|
||||
|
||||
@@ -17,6 +17,8 @@ export default class RhsThread extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.mounted = false;
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.onChangeAll = this.onChangeAll.bind(this);
|
||||
this.forceUpdateInfo = this.forceUpdateInfo.bind(this);
|
||||
@@ -50,8 +52,11 @@ export default class RhsThread extends React.Component {
|
||||
PostStore.addSelectedPostChangeListener(this.onChange);
|
||||
PostStore.addChangeListener(this.onChangeAll);
|
||||
PreferenceStore.addChangeListener(this.forceUpdateInfo);
|
||||
|
||||
this.resize();
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
|
||||
this.mounted = true;
|
||||
}
|
||||
componentDidUpdate() {
|
||||
if ($('.post-right__scroll')[0]) {
|
||||
@@ -63,7 +68,10 @@ export default class RhsThread extends React.Component {
|
||||
PostStore.removeSelectedPostChangeListener(this.onChange);
|
||||
PostStore.removeChangeListener(this.onChangeAll);
|
||||
PreferenceStore.removeChangeListener(this.forceUpdateInfo);
|
||||
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
|
||||
this.mounted = false;
|
||||
}
|
||||
forceUpdateInfo() {
|
||||
if (this.state.postList) {
|
||||
@@ -82,7 +90,7 @@ export default class RhsThread extends React.Component {
|
||||
}
|
||||
onChange() {
|
||||
var newState = this.getStateFromStores();
|
||||
if (!Utils.areObjectsEqual(newState, this.state)) {
|
||||
if (this.mounted && !Utils.areObjectsEqual(newState, this.state)) {
|
||||
this.setState(newState);
|
||||
}
|
||||
}
|
||||
@@ -120,7 +128,7 @@ export default class RhsThread extends React.Component {
|
||||
}
|
||||
|
||||
var newState = this.getStateFromStores();
|
||||
if (!Utils.areObjectsEqual(newState, this.state)) {
|
||||
if (this.mounted && !Utils.areObjectsEqual(newState, this.state)) {
|
||||
this.setState(newState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,9 +506,9 @@ export default class Sidebar extends React.Component {
|
||||
link.rel = 'shortcut icon';
|
||||
link.id = 'favicon';
|
||||
if (this.badgesActive) {
|
||||
link.href = '/static/images/redfavicon.ico';
|
||||
link.href = '/static/images/favicon/redfavicon-16x16.png';
|
||||
} else {
|
||||
link.href = '/static/images/favicon.ico';
|
||||
link.href = '/static/images/favicon/favicon-16x16.png';
|
||||
}
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var oldLink = document.getElementById('favicon');
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as Utils from '../utils/utils.jsx';
|
||||
import * as client from '../utils/client.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
export default class SignupUserComplete extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -51,7 +52,7 @@ export default class SignupUserComplete extends React.Component {
|
||||
return;
|
||||
} else if (usernameError) {
|
||||
this.setState({
|
||||
nameError: 'Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols \'.\', \'-\' and \'_\'.',
|
||||
nameError: 'Username must begin with a letter, and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + ' lowercase characters made up of numbers, letters, and the symbols \'.\', \'-\' and \'_\'.',
|
||||
emailError: '',
|
||||
passwordError: '',
|
||||
serverError: ''
|
||||
@@ -60,8 +61,8 @@ export default class SignupUserComplete extends React.Component {
|
||||
}
|
||||
|
||||
const providedPassword = ReactDOM.findDOMNode(this.refs.password).value.trim();
|
||||
if (!providedPassword || providedPassword.length < 5) {
|
||||
this.setState({nameError: '', emailError: '', passwordError: 'Please enter at least 5 characters', serverError: ''});
|
||||
if (!providedPassword || providedPassword.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
this.setState({nameError: '', emailError: '', passwordError: 'Please enter at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters', serverError: ''});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +112,7 @@ export default class SignupUserComplete extends React.Component {
|
||||
client.track('signup', 'signup_user_01_welcome');
|
||||
|
||||
if (this.state.wizard === 'finished') {
|
||||
return <div>You've already completed the signup process for this invitation or this invitation has expired.</div>;
|
||||
return <div>{"You've already completed the signup process for this invitation or this invitation has expired."}</div>;
|
||||
}
|
||||
|
||||
// set up error labels
|
||||
@@ -123,9 +124,11 @@ export default class SignupUserComplete extends React.Component {
|
||||
}
|
||||
|
||||
var nameError = null;
|
||||
var nameHelpText = <span className='help-block'>{'Username must begin with a letter, and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + " lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'"}</span>;
|
||||
var nameDivStyle = 'form-group';
|
||||
if (this.state.nameError) {
|
||||
nameError = <label className='control-label'>{this.state.nameError}</label>;
|
||||
nameHelpText = '';
|
||||
nameDivStyle += ' has-error';
|
||||
}
|
||||
|
||||
@@ -148,7 +151,7 @@ export default class SignupUserComplete extends React.Component {
|
||||
// set up the email entry and hide it if an email was provided
|
||||
var yourEmailIs = '';
|
||||
if (this.state.user.email) {
|
||||
yourEmailIs = <span>Your email address is <strong>{this.state.user.email}</strong>. You'll use this address to sign in to {global.window.mm_config.SiteName}.</span>;
|
||||
yourEmailIs = <span>{'Your email address is '}<strong>{this.state.user.email}</strong>{". You'll use this address to sign in to " + global.window.mm_config.SiteName + '.'}</span>;
|
||||
}
|
||||
|
||||
var emailContainerStyle = 'margin--extra';
|
||||
@@ -158,7 +161,7 @@ export default class SignupUserComplete extends React.Component {
|
||||
|
||||
var email = (
|
||||
<div className={emailContainerStyle}>
|
||||
<h5><strong>What's your email address?</strong></h5>
|
||||
<h5><strong>{"What's your email address?"}</strong></h5>
|
||||
<div className={emailDivStyle}>
|
||||
<input
|
||||
type='email'
|
||||
@@ -208,7 +211,7 @@ export default class SignupUserComplete extends React.Component {
|
||||
{email}
|
||||
{yourEmailIs}
|
||||
<div className='margin--extra'>
|
||||
<h5><strong>Choose your username</strong></h5>
|
||||
<h5><strong>{'Choose your username'}</strong></h5>
|
||||
<div className={nameDivStyle}>
|
||||
<input
|
||||
type='text'
|
||||
@@ -219,11 +222,11 @@ export default class SignupUserComplete extends React.Component {
|
||||
spellCheck='false'
|
||||
/>
|
||||
{nameError}
|
||||
<span className='help-block'>Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'</span>
|
||||
{nameHelpText}
|
||||
</div>
|
||||
</div>
|
||||
<div className='margin--extra'>
|
||||
<h5><strong>Choose your password</strong></h5>
|
||||
<h5><strong>{'Choose your password'}</strong></h5>
|
||||
<div className={passwordDivStyle}>
|
||||
<input
|
||||
type='password'
|
||||
@@ -243,7 +246,7 @@ export default class SignupUserComplete extends React.Component {
|
||||
onClick={this.handleSubmit}
|
||||
className='btn-primary btn'
|
||||
>
|
||||
Create Account
|
||||
{'Create Account'}
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
@@ -255,7 +258,7 @@ export default class SignupUserComplete extends React.Component {
|
||||
<div>
|
||||
{signupMessage}
|
||||
<div className='or__container'>
|
||||
<span>or</span>
|
||||
<span>{'or'}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -268,10 +271,10 @@ export default class SignupUserComplete extends React.Component {
|
||||
className='signup-team-logo'
|
||||
src='/static/images/logo.png'
|
||||
/>
|
||||
<h5 className='margin--less'>Welcome to:</h5>
|
||||
<h5 className='margin--less'>{'Welcome to:'}</h5>
|
||||
<h2 className='signup-team__name'>{this.props.teamDisplayName}</h2>
|
||||
<h2 className='signup-team__subdomain'>on {global.window.mm_config.SiteName}</h2>
|
||||
<h4 className='color--light'>Let's create your account</h4>
|
||||
<h2 className='signup-team__subdomain'>{'on ' + global.window.mm_config.SiteName}</h2>
|
||||
<h4 className='color--light'>{"Let's create your account"}</h4>
|
||||
{signupMessage}
|
||||
{emailSignup}
|
||||
{serverError}
|
||||
|
||||
@@ -66,7 +66,7 @@ export default class GeneralTab extends React.Component {
|
||||
|
||||
handleTeamListingRadio(listing) {
|
||||
if (global.window.mm_config.EnableTeamListing !== 'true' && listing) {
|
||||
this.setState({clientError: 'Team directory has been disabled. Please ask a system admin to enable it.'});
|
||||
this.setState({clientError: 'Team Directory has been disabled. Please ask a System Admin to enable the Team Directory in the System Console team settings.'});
|
||||
} else {
|
||||
this.setState({allow_team_listing: listing});
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
export default class TeamSignupPasswordPage extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -23,8 +24,8 @@ export default class TeamSignupPasswordPage extends React.Component {
|
||||
e.preventDefault();
|
||||
|
||||
var password = ReactDOM.findDOMNode(this.refs.password).value.trim();
|
||||
if (!password || password.length < 5) {
|
||||
this.setState({passwordError: 'Please enter at least 5 characters'});
|
||||
if (!password || password.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
this.setState({passwordError: 'Please enter at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters'});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,15 +93,15 @@ export default class TeamSignupPasswordPage extends React.Component {
|
||||
className='signup-team-logo'
|
||||
src='/static/images/logo.png'
|
||||
/>
|
||||
<h2 className='margin--less'>Your password</h2>
|
||||
<h5 className='color--light'>Select a password that you'll use to login with your email address:</h5>
|
||||
<h2 className='margin--less'>{'Your password'}</h2>
|
||||
<h5 className='color--light'>{"Select a password that you'll use to login with your email address:"}</h5>
|
||||
<div className='inner__content margin--extra'>
|
||||
<h5><strong>Email</strong></h5>
|
||||
<h5><strong>{'Email'}</strong></h5>
|
||||
<div className='block--gray form-group'>{this.props.state.team.email}</div>
|
||||
<div className={passwordDivStyle}>
|
||||
<div className='row'>
|
||||
<div className='col-sm-11'>
|
||||
<h5><strong>Choose your password</strong></h5>
|
||||
<h5><strong>{'Choose your password'}</strong></h5>
|
||||
<input
|
||||
autoFocus={true}
|
||||
type='password'
|
||||
@@ -110,7 +111,7 @@ export default class TeamSignupPasswordPage extends React.Component {
|
||||
maxLength='128'
|
||||
spellCheck='false'
|
||||
/>
|
||||
<span className='color--light help-block'>Passwords must contain 5 to 50 characters. Your password will be strongest if it contains a mix of symbols, numbers, and upper and lowercase characters.</span>
|
||||
<span className='color--light help-block'>{'Passwords must contain ' + Constants.MIN_PASSWORD_LENGTH + ' to ' + Constants.MAX_PASSWORD_LENGTH + ' characters. Your password will be strongest if it contains a mix of symbols, numbers, and upper and lowercase characters.'}</span>
|
||||
</div>
|
||||
</div>
|
||||
{passwordError}
|
||||
@@ -125,7 +126,7 @@ export default class TeamSignupPasswordPage extends React.Component {
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Creating team...'}
|
||||
onClick={this.submitNext}
|
||||
>
|
||||
Finish
|
||||
{'Finish'}
|
||||
</button>
|
||||
</div>
|
||||
<p>By proceeding to create your account and use {global.window.mm_config.SiteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {global.window.mm_config.SiteName}.</p>
|
||||
@@ -134,7 +135,7 @@ export default class TeamSignupPasswordPage extends React.Component {
|
||||
href='#'
|
||||
onClick={this.submitBack}
|
||||
>
|
||||
Back to previous step
|
||||
{'Back to previous step'}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
export default class TeamSignupUsernamePage extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -33,7 +34,7 @@ export default class TeamSignupUsernamePage extends React.Component {
|
||||
this.setState({nameError: 'This username is reserved, please choose a new one.'});
|
||||
return;
|
||||
} else if (usernameError) {
|
||||
this.setState({nameError: 'Username must begin with a letter, and contain 3 to 15 characters in total, which may be numbers, lowercase letters, or any of the symbols \'.\', \'-\', or \'_\''});
|
||||
this.setState({nameError: 'Username must begin with a letter, and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + ' characters in total, which may be numbers, lowercase letters, or any of the symbols \'.\', \'-\', or \'_\''});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,9 +46,11 @@ export default class TeamSignupUsernamePage extends React.Component {
|
||||
Client.track('signup', 'signup_team_06_username');
|
||||
|
||||
var nameError = null;
|
||||
var nameHelpText = <span className='color--light help-block'>{'Usernames must begin with a letter and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + " characters made up of lowercase letters, numbers, and the symbols '.', '-' and '_'"}</span>;
|
||||
var nameDivClass = 'form-group';
|
||||
if (this.state.nameError) {
|
||||
nameError = <label className='control-label'>{this.state.nameError}</label>;
|
||||
nameHelpText = '';
|
||||
nameDivClass += ' has-error';
|
||||
}
|
||||
|
||||
@@ -58,13 +61,13 @@ export default class TeamSignupUsernamePage extends React.Component {
|
||||
className='signup-team-logo'
|
||||
src='/static/images/logo.png'
|
||||
/>
|
||||
<h2 className='margin--less'>Your username</h2>
|
||||
<h2 className='margin--less'>{'Your username'}</h2>
|
||||
<h5 className='color--light'>{'Select a memorable username that makes it easy for teammates to identify you:'}</h5>
|
||||
<div className='inner__content margin--extra'>
|
||||
<div className={nameDivClass}>
|
||||
<div className='row'>
|
||||
<div className='col-sm-11'>
|
||||
<h5><strong>Choose your username</strong></h5>
|
||||
<h5><strong>{'Choose your username'}</strong></h5>
|
||||
<input
|
||||
autoFocus={true}
|
||||
type='text'
|
||||
@@ -75,7 +78,7 @@ export default class TeamSignupUsernamePage extends React.Component {
|
||||
maxLength='128'
|
||||
spellCheck='false'
|
||||
/>
|
||||
<span className='color--light help-block'>Usernames must begin with a letter and contain 3 to 15 characters made up of lowercase letters, numbers, and the symbols '.', '-' and '_'</span>
|
||||
{nameHelpText}
|
||||
</div>
|
||||
</div>
|
||||
{nameError}
|
||||
@@ -86,7 +89,7 @@ export default class TeamSignupUsernamePage extends React.Component {
|
||||
className='btn btn-primary margin--extra'
|
||||
onClick={this.submitNext}
|
||||
>
|
||||
Next
|
||||
{'Next'}
|
||||
<i className='glyphicon glyphicon-chevron-right'></i>
|
||||
</button>
|
||||
<div className='margin--extra'>
|
||||
@@ -94,7 +97,7 @@ export default class TeamSignupUsernamePage extends React.Component {
|
||||
href='#'
|
||||
onClick={this.submitBack}
|
||||
>
|
||||
Back to previous step
|
||||
{'Back to previous step'}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -22,8 +22,6 @@ export default class Textbox extends React.Component {
|
||||
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
this.handleFocus = this.handleFocus.bind(this);
|
||||
this.handleBlur = this.handleBlur.bind(this);
|
||||
this.showPreview = this.showPreview.bind(this);
|
||||
|
||||
this.state = {
|
||||
@@ -81,54 +79,46 @@ export default class Textbox extends React.Component {
|
||||
}
|
||||
|
||||
resize() {
|
||||
const e = this.refs.message.getTextbox();
|
||||
const w = ReactDOM.findDOMNode(this.refs.wrapper);
|
||||
const textbox = this.refs.message.getTextbox();
|
||||
const $textbox = $(textbox);
|
||||
const $wrapper = $(ReactDOM.findDOMNode(this.refs.wrapper));
|
||||
|
||||
const prevHeight = $(e).height();
|
||||
const padding = parseInt($textbox.css('padding-bottom'), 10) + parseInt($textbox.css('padding-top'), 10);
|
||||
const borders = parseInt($textbox.css('border-bottom-width'), 10) + parseInt($textbox.css('border-top-width'), 10);
|
||||
const maxHeight = parseInt($textbox.css('max-height'), 10) - borders;
|
||||
|
||||
const lht = parseInt($(e).css('lineHeight'), 10);
|
||||
const lines = e.scrollHeight / lht;
|
||||
let mod = 15;
|
||||
const prevHeight = $textbox.height();
|
||||
|
||||
if (lines < 2.5 || this.props.messageText === '') {
|
||||
mod = 30;
|
||||
}
|
||||
// set the height to auto and remove the scrollbar so we can get the actual size of the contents
|
||||
$textbox.css('height', 'auto').css('overflow-y', 'hidden');
|
||||
|
||||
if (e.scrollHeight - mod < 167) {
|
||||
$(e).css({height: 'auto', 'overflow-y': 'hidden'}).height(e.scrollHeight - mod);
|
||||
$(w).css({height: 'auto'}).height(e.scrollHeight + 2);
|
||||
$(w).closest('.post-body__cell').removeClass('scroll');
|
||||
if (this.state.preview) {
|
||||
$(ReactDOM.findDOMNode(this.refs.preview)).css({height: 'auto', 'overflow-y': 'auto'}).height(e.scrollHeight - mod);
|
||||
}
|
||||
let height = textbox.scrollHeight - padding;
|
||||
|
||||
if (height + padding > maxHeight) {
|
||||
height = maxHeight - padding;
|
||||
|
||||
// turn scrollbar on and move over attachment icon to compensate for that
|
||||
$textbox.css('overflow-y', 'scroll');
|
||||
$wrapper.closest('.post-body__cell').addClass('scroll');
|
||||
} else {
|
||||
$(e).css({height: 'auto', 'overflow-y': 'scroll'}).height(167 - mod);
|
||||
$(w).css({height: 'auto'}).height(163);
|
||||
$(w).closest('.post-body__cell').addClass('scroll');
|
||||
if (this.state.preview) {
|
||||
$(ReactDOM.findDOMNode(this.refs.preview)).css({height: 'auto', 'overflow-y': 'scroll'}).height(163);
|
||||
}
|
||||
$wrapper.closest('.post-body__cell').removeClass('scroll');
|
||||
}
|
||||
|
||||
if (prevHeight !== $(e).height() && this.props.onHeightChange) {
|
||||
// set the textarea to be the proper height
|
||||
$textbox.height(height);
|
||||
|
||||
// set the wrapper height to match the height of the textbox including padding and borders
|
||||
$wrapper.height(height + padding + borders);
|
||||
|
||||
if (this.state.preview) {
|
||||
$(ReactDOM.findDOMNode(this.refs.preview)).height(height + borders);
|
||||
}
|
||||
|
||||
if (height !== prevHeight && this.props.onHeightChange) {
|
||||
this.props.onHeightChange();
|
||||
}
|
||||
}
|
||||
|
||||
handleFocus() {
|
||||
const elm = this.refs.message.getTextbox();
|
||||
if (elm.title === elm.value) {
|
||||
elm.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
const elm = this.refs.message.getTextbox();
|
||||
if (elm.value === '') {
|
||||
elm.value = elm.title;
|
||||
}
|
||||
}
|
||||
|
||||
showPreview(e) {
|
||||
e.preventDefault();
|
||||
e.target.blur();
|
||||
@@ -178,9 +168,6 @@ export default class Textbox extends React.Component {
|
||||
onUserInput={this.props.onUserInput}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
onPaste={this.handlePaste}
|
||||
style={{visibility: this.state.preview ? 'hidden' : 'visible'}}
|
||||
listComponent={SuggestionList}
|
||||
providers={this.suggestionProviders}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default class UnreadChannelIndicator extends React.Component {
|
||||
render() {
|
||||
let displayValue = 'none';
|
||||
if (this.props.show) {
|
||||
displayValue = 'initial';
|
||||
displayValue = 'block';
|
||||
}
|
||||
return (
|
||||
<div
|
||||
|
||||
101
web/react/components/user_settings/manage_languages.jsx
Обычный файл
101
web/react/components/user_settings/manage_languages.jsx
Обычный файл
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
export default class ManageLanguage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setupInitialState = this.setupInitialState.bind(this);
|
||||
this.setLanguage = this.setLanguage.bind(this);
|
||||
this.changeLanguage = this.changeLanguage.bind(this);
|
||||
this.submitUser = this.submitUser.bind(this);
|
||||
this.state = this.setupInitialState(props);
|
||||
}
|
||||
setupInitialState(props) {
|
||||
var user = props.user;
|
||||
return {
|
||||
languages: Utils.languages(),
|
||||
locale: user.locale
|
||||
};
|
||||
}
|
||||
setLanguage(e) {
|
||||
this.setState({locale: e.target.value});
|
||||
}
|
||||
changeLanguage(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var user = this.props.user;
|
||||
var locale = this.state.locale;
|
||||
|
||||
user.locale = locale;
|
||||
|
||||
this.submitUser(user);
|
||||
}
|
||||
submitUser(user) {
|
||||
Client.updateUser(user,
|
||||
() => {
|
||||
window.location.reload(true);
|
||||
},
|
||||
(err) => {
|
||||
let serverError;
|
||||
if (err.message) {
|
||||
serverError = err.message;
|
||||
} else {
|
||||
serverError = err;
|
||||
}
|
||||
this.setState({serverError});
|
||||
}
|
||||
);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
if (this.state.serverError) {
|
||||
serverError = <label className='has-error'>{this.state.serverError}</label>;
|
||||
}
|
||||
|
||||
const options = [];
|
||||
this.state.languages.forEach((lang) => {
|
||||
options.push(
|
||||
<option
|
||||
key={lang.value}
|
||||
value={lang.value}
|
||||
>
|
||||
{lang.name}
|
||||
</option>);
|
||||
});
|
||||
|
||||
return (
|
||||
<div key='changeLanguage'>
|
||||
<br/>
|
||||
<label className='control-label'>{'Change interface language'}</label>
|
||||
<div className='padding-top'>
|
||||
<select
|
||||
ref='language'
|
||||
className='form-control'
|
||||
value={this.state.locale}
|
||||
onChange={this.setLanguage}
|
||||
>
|
||||
{options}
|
||||
</select>
|
||||
{serverError}
|
||||
<div className='padding-top'>
|
||||
<a
|
||||
className={'btn btn-sm btn-primary'}
|
||||
href='#'
|
||||
onClick={this.changeLanguage}
|
||||
>
|
||||
{'Set language'}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ManageLanguage.propTypes = {
|
||||
user: React.PropTypes.object
|
||||
};
|
||||
@@ -5,7 +5,9 @@ import {savePreferences} from '../../utils/client.jsx';
|
||||
import SettingItemMin from '../setting_item_min.jsx';
|
||||
import SettingItemMax from '../setting_item_max.jsx';
|
||||
import Constants from '../../utils/constants.jsx';
|
||||
const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
|
||||
import PreferenceStore from '../../stores/preference_store.jsx';
|
||||
import ManageLanguages from './manage_languages.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
function getDisplayStateFromStores() {
|
||||
@@ -78,6 +80,7 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
let clockSection;
|
||||
let nameFormatSection;
|
||||
let fontSection;
|
||||
let languagesSection;
|
||||
|
||||
if (this.props.activeSection === 'clock') {
|
||||
const clockFormat = [false, false];
|
||||
@@ -292,6 +295,48 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (Utils.isFeatureEnabled(PreReleaseFeatures.LOC_PREVIEW)) {
|
||||
if (this.props.activeSection === 'languages') {
|
||||
var inputs = [];
|
||||
inputs.push(
|
||||
<ManageLanguages
|
||||
user={this.props.user}
|
||||
key='languages-ui'
|
||||
/>
|
||||
);
|
||||
|
||||
languagesSection = (
|
||||
<SettingItemMax
|
||||
title={'Language'}
|
||||
width='medium'
|
||||
inputs={inputs}
|
||||
updateSection={(e) => {
|
||||
this.updateSection('');
|
||||
e.preventDefault();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
var locale = 'English';
|
||||
Utils.languages().forEach((l) => {
|
||||
if (l.value === this.props.user.locale) {
|
||||
locale = l.name;
|
||||
}
|
||||
});
|
||||
|
||||
languagesSection = (
|
||||
<SettingItemMin
|
||||
title={'Language'}
|
||||
width='medium'
|
||||
describe={locale}
|
||||
updateSection={() => {
|
||||
this.updateSection('languages');
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='modal-header'>
|
||||
@@ -324,6 +369,7 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
<div className='divider-dark'/>
|
||||
{nameFormatSection}
|
||||
<div className='divider-dark'/>
|
||||
{languagesSection}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -47,7 +47,7 @@ export default class UserSettingsGeneralTab extends React.Component {
|
||||
this.setState({clientError: 'This username is reserved, please choose a new one.'});
|
||||
return;
|
||||
} else if (usernameError) {
|
||||
this.setState({clientError: "Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'."});
|
||||
this.setState({clientError: 'Username must begin with a letter, and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + " lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'."});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -493,7 +493,7 @@ export default class UserSettingsGeneralTab extends React.Component {
|
||||
);
|
||||
|
||||
submit = this.submitEmail;
|
||||
} else {
|
||||
} else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) {
|
||||
inputs.push(
|
||||
<div
|
||||
key='oauthEmailInfo'
|
||||
@@ -531,7 +531,7 @@ export default class UserSettingsGeneralTab extends React.Component {
|
||||
} else {
|
||||
describe = UserStore.getCurrentUser().email;
|
||||
}
|
||||
} else {
|
||||
} else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) {
|
||||
describe = 'Log in done through GitLab';
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ export default class SecurityTab extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPassword.length < 5) {
|
||||
this.setState({passwordError: 'New passwords must be at least 5 characters', serverError: ''});
|
||||
if (newPassword.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
this.setState({passwordError: 'New passwords must be at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters', serverError: ''});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ export default class SecurityTab extends React.Component {
|
||||
className='security-links theme'
|
||||
dialogType={AccessHistoryModal}
|
||||
>
|
||||
<i className='fa fa-clock-o'></i>View Access History
|
||||
<i className='fa fa-clock-o'></i>{'View Access History'}
|
||||
</ToggleModalButton>
|
||||
<b> </b>
|
||||
<ToggleModalButton
|
||||
|
||||
@@ -211,7 +211,7 @@ export default class ViewImageModal extends React.Component {
|
||||
}
|
||||
|
||||
const filename = this.props.filenames[this.state.imgId];
|
||||
const fileUrl = Utils.getFileUrl(filename);
|
||||
const fileUrl = Utils.getFileUrl(filename, true);
|
||||
|
||||
var content;
|
||||
if (this.state.loaded[this.state.imgId]) {
|
||||
@@ -377,6 +377,7 @@ function ImagePreview({filename, fileUrl, fileInfo, maxHeight}) {
|
||||
<a
|
||||
href={fileUrl}
|
||||
target='_blank'
|
||||
download={true}
|
||||
>
|
||||
<img
|
||||
style={{maxHeight}}
|
||||
|
||||
@@ -1,17 +1,66 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import Login from '../components/login.jsx';
|
||||
|
||||
function setupLoginPage(props) {
|
||||
ReactDOM.render(
|
||||
<Login
|
||||
teamDisplayName={props.TeamDisplayName}
|
||||
teamName={props.TeamName}
|
||||
inviteId={props.InviteId}
|
||||
/>,
|
||||
document.getElementById('login')
|
||||
);
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<Login
|
||||
teamDisplayName={this.props.map.TeamDisplayName}
|
||||
teamName={this.props.map.TeamName}
|
||||
inviteId={this.props.map.InviteId}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_login_page = setupLoginPage;
|
||||
global.window.setup_login_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props} />,
|
||||
document.getElementById('login')
|
||||
);
|
||||
};
|
||||
@@ -49,7 +49,7 @@ class SocketStoreClass extends EventEmitter {
|
||||
protocol = 'wss://';
|
||||
}
|
||||
|
||||
var connUrl = protocol + location.host + '/api/v1/websocket?' + Utils.getSessionIndex();
|
||||
var connUrl = protocol + location.host + ((/:\d+/).test(location.host) ? '' : Utils.getWebsocketPort(protocol)) + '/api/v1/websocket?' + Utils.getSessionIndex();
|
||||
|
||||
if (this.failCount === 0) {
|
||||
console.log('websocket connecting to ' + connUrl); //eslint-disable-line no-console
|
||||
|
||||
@@ -60,6 +60,18 @@ function handleError(methodName, xhr, status, err) {
|
||||
return e;
|
||||
}
|
||||
|
||||
export function getTranslations(locale, success, error) {
|
||||
$.ajax({
|
||||
url: '/static/i18n/' + locale + '.json',
|
||||
dataType: 'json',
|
||||
success,
|
||||
error: function onError(xhr, status, err) {
|
||||
var e = handleError('getTranslations', xhr, status, err);
|
||||
error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function createTeamFromSignup(teamSignup, success, error) {
|
||||
$.ajax({
|
||||
url: '/api/v1/teams/create_from_signup',
|
||||
|
||||
@@ -451,7 +451,15 @@ export default {
|
||||
EMBED_PREVIEW: {
|
||||
label: 'embed_preview',
|
||||
description: 'Show preview snippet of links below message'
|
||||
},
|
||||
LOC_PREVIEW: {
|
||||
label: 'loc_preview',
|
||||
description: 'Show user language in display settings'
|
||||
}
|
||||
},
|
||||
OVERLAY_TIME_DELAY: 400
|
||||
OVERLAY_TIME_DELAY: 400,
|
||||
MIN_USERNAME_LENGTH: 3,
|
||||
MAX_USERNAME_LENGTH: 15,
|
||||
MIN_PASSWORD_LENGTH: 5,
|
||||
MAX_PASSWORD_LENGTH: 50
|
||||
};
|
||||
|
||||
16
web/react/utils/locales/en.js
Обычный файл
16
web/react/utils/locales/en.js
Обычный файл
@@ -0,0 +1,16 @@
|
||||
// GENERATED FILE
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports["default"] = [{ "locale": "en", "pluralRuleFunction": function pluralRuleFunction(n, ord) {
|
||||
var s = String(n).split("."),
|
||||
v0 = !s[1],
|
||||
t0 = Number(s[0]) == n,
|
||||
n10 = t0 && s[0].slice(-1),
|
||||
n100 = t0 && s[0].slice(-2);if (ord) return n10 == 1 && n100 != 11 ? "one" : n10 == 2 && n100 != 12 ? "two" : n10 == 3 && n100 != 13 ? "few" : "other";return n == 1 && v0 ? "one" : "other";
|
||||
}, "fields": { "year": { "displayName": "Year", "relative": { "0": "this year", "1": "next year", "-1": "last year" }, "relativeTime": { "future": { "one": "in {0} year", "other": "in {0} years" }, "past": { "one": "{0} year ago", "other": "{0} years ago" } } }, "month": { "displayName": "Month", "relative": { "0": "this month", "1": "next month", "-1": "last month" }, "relativeTime": { "future": { "one": "in {0} month", "other": "in {0} months" }, "past": { "one": "{0} month ago", "other": "{0} months ago" } } }, "day": { "displayName": "Day", "relative": { "0": "today", "1": "tomorrow", "-1": "yesterday" }, "relativeTime": { "future": { "one": "in {0} day", "other": "in {0} days" }, "past": { "one": "{0} day ago", "other": "{0} days ago" } } }, "hour": { "displayName": "Hour", "relativeTime": { "future": { "one": "in {0} hour", "other": "in {0} hours" }, "past": { "one": "{0} hour ago", "other": "{0} hours ago" } } }, "minute": { "displayName": "Minute", "relativeTime": { "future": { "one": "in {0} minute", "other": "in {0} minutes" }, "past": { "one": "{0} minute ago", "other": "{0} minutes ago" } } }, "second": { "displayName": "Second", "relative": { "0": "now" }, "relativeTime": { "future": { "one": "in {0} second", "other": "in {0} seconds" }, "past": { "one": "{0} second ago", "other": "{0} seconds ago" } } } } }, { "locale": "en-001", "parentLocale": "en" }, { "locale": "en-150", "parentLocale": "en-GB" }, { "locale": "en-GB", "parentLocale": "en-001" }, { "locale": "en-AG", "parentLocale": "en-001" }, { "locale": "en-AI", "parentLocale": "en-001" }, { "locale": "en-AS", "parentLocale": "en" }, { "locale": "en-AU", "parentLocale": "en-GB", "fields": { "year": { "displayName": "Year", "relative": { "0": "This year", "1": "Next year", "-1": "Last year" }, "relativeTime": { "future": { "one": "in {0} year", "other": "in {0} years" }, "past": { "one": "{0} year ago", "other": "{0} years ago" } } }, "month": { "displayName": "Month", "relative": { "0": "This month", "1": "Next month", "-1": "Last month" }, "relativeTime": { "future": { "one": "in {0} month", "other": "in {0} months" }, "past": { "one": "{0} month ago", "other": "{0} months ago" } } }, "day": { "displayName": "Day", "relative": { "0": "today", "1": "tomorrow", "-1": "yesterday" }, "relativeTime": { "future": { "one": "in {0} day", "other": "in {0} days" }, "past": { "one": "{0} day ago", "other": "{0} days ago" } } }, "hour": { "displayName": "Hour", "relativeTime": { "future": { "one": "in {0} hour", "other": "in {0} hours" }, "past": { "one": "{0} hour ago", "other": "{0} hours ago" } } }, "minute": { "displayName": "Minute", "relativeTime": { "future": { "one": "in {0} minute", "other": "in {0} minutes" }, "past": { "one": "{0} minute ago", "other": "{0} minutes ago" } } }, "second": { "displayName": "Second", "relative": { "0": "now" }, "relativeTime": { "future": { "one": "in {0} second", "other": "in {0} seconds" }, "past": { "one": "{0} second ago", "other": "{0} seconds ago" } } } } }, { "locale": "en-BB", "parentLocale": "en-001" }, { "locale": "en-BE", "parentLocale": "en-GB" }, { "locale": "en-BM", "parentLocale": "en-001" }, { "locale": "en-BS", "parentLocale": "en-001" }, { "locale": "en-BW", "parentLocale": "en-001" }, { "locale": "en-BZ", "parentLocale": "en-001" }, { "locale": "en-CA", "parentLocale": "en" }, { "locale": "en-CC", "parentLocale": "en-001" }, { "locale": "en-CK", "parentLocale": "en-001" }, { "locale": "en-CM", "parentLocale": "en-001" }, { "locale": "en-CX", "parentLocale": "en-001" }, { "locale": "en-DG", "parentLocale": "en-GB" }, { "locale": "en-DM", "parentLocale": "en-001" }, { "locale": "en-Dsrt", "pluralRuleFunction": function pluralRuleFunction(n, ord) {
|
||||
if (ord) return "other";return "other";
|
||||
}, "fields": { "year": { "displayName": "Year", "relative": { "0": "this year", "1": "next year", "-1": "last year" }, "relativeTime": { "future": { "other": "+{0} y" }, "past": { "other": "-{0} y" } } }, "month": { "displayName": "Month", "relative": { "0": "this month", "1": "next month", "-1": "last month" }, "relativeTime": { "future": { "other": "+{0} m" }, "past": { "other": "-{0} m" } } }, "day": { "displayName": "Day", "relative": { "0": "today", "1": "tomorrow", "-1": "yesterday" }, "relativeTime": { "future": { "other": "+{0} d" }, "past": { "other": "-{0} d" } } }, "hour": { "displayName": "Hour", "relativeTime": { "future": { "other": "+{0} h" }, "past": { "other": "-{0} h" } } }, "minute": { "displayName": "Minute", "relativeTime": { "future": { "other": "+{0} min" }, "past": { "other": "-{0} min" } } }, "second": { "displayName": "Second", "relative": { "0": "now" }, "relativeTime": { "future": { "other": "+{0} s" }, "past": { "other": "-{0} s" } } } } }, { "locale": "en-ER", "parentLocale": "en-001" }, { "locale": "en-FJ", "parentLocale": "en-001" }, { "locale": "en-FK", "parentLocale": "en-GB" }, { "locale": "en-FM", "parentLocale": "en-001" }, { "locale": "en-GD", "parentLocale": "en-001" }, { "locale": "en-GG", "parentLocale": "en-GB" }, { "locale": "en-GH", "parentLocale": "en-001" }, { "locale": "en-GI", "parentLocale": "en-GB" }, { "locale": "en-GM", "parentLocale": "en-001" }, { "locale": "en-GU", "parentLocale": "en" }, { "locale": "en-GY", "parentLocale": "en-001" }, { "locale": "en-HK", "parentLocale": "en-GB" }, { "locale": "en-IE", "parentLocale": "en-GB" }, { "locale": "en-IM", "parentLocale": "en-GB" }, { "locale": "en-IN", "parentLocale": "en-GB" }, { "locale": "en-IO", "parentLocale": "en-GB" }, { "locale": "en-JE", "parentLocale": "en-GB" }, { "locale": "en-JM", "parentLocale": "en-001" }, { "locale": "en-KE", "parentLocale": "en-001" }, { "locale": "en-KI", "parentLocale": "en-001" }, { "locale": "en-KN", "parentLocale": "en-001" }, { "locale": "en-KY", "parentLocale": "en-001" }, { "locale": "en-LC", "parentLocale": "en-001" }, { "locale": "en-LR", "parentLocale": "en-001" }, { "locale": "en-LS", "parentLocale": "en-001" }, { "locale": "en-MG", "parentLocale": "en-001" }, { "locale": "en-MH", "parentLocale": "en" }, { "locale": "en-MO", "parentLocale": "en-GB" }, { "locale": "en-MP", "parentLocale": "en" }, { "locale": "en-MS", "parentLocale": "en-001" }, { "locale": "en-MT", "parentLocale": "en-GB" }, { "locale": "en-MU", "parentLocale": "en-001" }, { "locale": "en-MW", "parentLocale": "en-001" }, { "locale": "en-MY", "parentLocale": "en-001" }, { "locale": "en-NA", "parentLocale": "en-001" }, { "locale": "en-NF", "parentLocale": "en-001" }, { "locale": "en-NG", "parentLocale": "en-001" }, { "locale": "en-NR", "parentLocale": "en-001" }, { "locale": "en-NU", "parentLocale": "en-001" }, { "locale": "en-NZ", "parentLocale": "en-GB" }, { "locale": "en-PG", "parentLocale": "en-001" }, { "locale": "en-PH", "parentLocale": "en-001" }, { "locale": "en-PK", "parentLocale": "en-GB" }, { "locale": "en-PN", "parentLocale": "en-001" }, { "locale": "en-PR", "parentLocale": "en" }, { "locale": "en-PW", "parentLocale": "en-001" }, { "locale": "en-RW", "parentLocale": "en-001" }, { "locale": "en-SB", "parentLocale": "en-001" }, { "locale": "en-SC", "parentLocale": "en-001" }, { "locale": "en-SD", "parentLocale": "en-001" }, { "locale": "en-SG", "parentLocale": "en-GB" }, { "locale": "en-SH", "parentLocale": "en-GB" }, { "locale": "en-SL", "parentLocale": "en-001" }, { "locale": "en-SS", "parentLocale": "en-001" }, { "locale": "en-SX", "parentLocale": "en-001" }, { "locale": "en-SZ", "parentLocale": "en-001" }, { "locale": "en-TC", "parentLocale": "en-001" }, { "locale": "en-TK", "parentLocale": "en-001" }, { "locale": "en-TO", "parentLocale": "en-001" }, { "locale": "en-TT", "parentLocale": "en-001" }, { "locale": "en-TV", "parentLocale": "en-001" }, { "locale": "en-TZ", "parentLocale": "en-001" }, { "locale": "en-UG", "parentLocale": "en-001" }, { "locale": "en-UM", "parentLocale": "en" }, { "locale": "en-US", "parentLocale": "en" }, { "locale": "en-US-POSIX", "parentLocale": "en-US" }, { "locale": "en-VC", "parentLocale": "en-001" }, { "locale": "en-VG", "parentLocale": "en-GB" }, { "locale": "en-VI", "parentLocale": "en" }, { "locale": "en-VU", "parentLocale": "en-001" }, { "locale": "en-WS", "parentLocale": "en-001" }, { "locale": "en-ZA", "parentLocale": "en-001" }, { "locale": "en-ZM", "parentLocale": "en-001" }, { "locale": "en-ZW", "parentLocale": "en-001" }];
|
||||
module.exports = exports["default"];
|
||||
10
web/react/utils/locales/es.js
Обычный файл
10
web/react/utils/locales/es.js
Обычный файл
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
@@ -879,8 +879,8 @@ export function isValidUsername(name) {
|
||||
var error = '';
|
||||
if (!name) {
|
||||
error = 'This field is required';
|
||||
} else if (name.length < 3 || name.length > 15) {
|
||||
error = 'Must be between 3 and 15 characters';
|
||||
} else if (name.length < Constants.MIN_USERNAME_LENGTH || name.length > Constants.MAX_USERNAME_LENGTH) {
|
||||
error = 'Must be between ' + Constants.MIN_USERNAME_LENGTH + ' and ' + Constants.MAX_USERNAME_LENGTH + ' characters';
|
||||
} else if (!(/^[a-z0-9\.\-\_]+$/).test(name)) {
|
||||
error = "Must contain only letters, numbers, and the symbols '.', '-', and '_'.";
|
||||
} else if (!(/[a-z]/).test(name.charAt(0))) { //eslint-disable-line no-negated-condition
|
||||
@@ -1091,8 +1091,9 @@ export function fileSizeToString(bytes) {
|
||||
}
|
||||
|
||||
// Converts a filename (like those attached to Post objects) to a url that can be used to retrieve attachments from the server.
|
||||
export function getFileUrl(filename) {
|
||||
return getWindowLocationOrigin() + '/api/v1/files/get' + filename + '?' + getSessionIndex();
|
||||
export function getFileUrl(filename, isDownload) {
|
||||
const downloadParam = isDownload ? '&download=1' : '';
|
||||
return getWindowLocationOrigin() + '/api/v1/files/get' + filename + '?' + getSessionIndex() + downloadParam;
|
||||
}
|
||||
|
||||
// Gets the name of a file (including extension) from a given url or file path.
|
||||
@@ -1101,6 +1102,17 @@ export function getFileName(path) {
|
||||
return split[split.length - 1];
|
||||
}
|
||||
|
||||
// Gets the websocket port to use. Configurable on the server.
|
||||
export function getWebsocketPort(protocol) {
|
||||
if ((/^wss:/).test(protocol)) { // wss://
|
||||
return ':' + global.window.mm_config.WebsocketSecurePort;
|
||||
}
|
||||
if ((/^ws:/).test(protocol)) {
|
||||
return ':' + global.window.mm_config.WebsocketPort;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function getSessionIndex() {
|
||||
if (global.window.mm_session_token_index >= 0) {
|
||||
return 'session_token_index=' + global.window.mm_session_token_index;
|
||||
@@ -1309,6 +1321,10 @@ export function fillArray(value, length) {
|
||||
// Checks if a data transfer contains files not text, folders, etc..
|
||||
// Slightly modified from http://stackoverflow.com/questions/6848043/how-do-i-detect-a-file-is-being-dragged-rather-than-a-draggable-element-on-my-pa
|
||||
export function isFileTransfer(files) {
|
||||
if (isBrowserIE()) {
|
||||
return files.types != null && files.types.contains('Files');
|
||||
}
|
||||
|
||||
return files.types != null && (files.types.indexOf ? files.types.indexOf('Files') !== -1 : files.types.contains('application/x-moz-file'));
|
||||
}
|
||||
|
||||
@@ -1324,3 +1340,18 @@ export function clearFileInput(elm) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
export function languages() {
|
||||
return (
|
||||
[
|
||||
{
|
||||
value: 'en',
|
||||
name: 'English'
|
||||
},
|
||||
{
|
||||
value: 'es',
|
||||
name: 'Español'
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user