summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ui/app/components/list_editor/index.js24
-rw-r--r--ui/app/components/login.js145
-rw-r--r--ui/app/components/main_panel/user_password_form.js54
-rw-r--r--ui/app/components/password_field.js28
-rw-r--r--ui/app/components/wizard/provider_select_stage.js32
5 files changed, 189 insertions, 94 deletions
diff --git a/ui/app/components/list_editor/index.js b/ui/app/components/list_editor/index.js
index 58b6ec4..4fff1ca 100644
--- a/ui/app/components/list_editor/index.js
+++ b/ui/app/components/list_editor/index.js
@@ -20,7 +20,8 @@ class ListEdit extends React.Component {
selected: null, // string of the selected item
onRemove: null,
onAdd: null,
- onSelect: null
+ onSelect: null,
+ onKeyDown: null
}}
constructor(props) {
@@ -64,6 +65,18 @@ class ListEdit extends React.Component {
}
}
+ componentDidMount() {
+ if (this.props.onKeyDown) {
+ this.listEditorDiv.addEventListener("keydown", this.props.onKeyDown)
+ }
+ }
+
+ componentWillUnmount() {
+ if (this.props.onKeyDown) {
+ this.listEditorDiv.removeEventListener("keydown", this.props.onKeyDown)
+ }
+ }
+
render() {
let options = null
if (this.props.items) {
@@ -72,11 +85,16 @@ class ListEdit extends React.Component {
}, this)
}
return(
- <div className="list-editor">
+ <div
+ ref={(div) => { this.listEditorDiv = div; }}
+ className="list-editor" >
<FormControl
value={this.row(this.props.selected)}
className="list-select"
- componentClass="select" size="5" onChange={this.click}>
+ componentClass="select"
+ size="5"
+ onChange={this.click}
+ >
{options}
</FormControl>
<ButtonToolbar className="pull-right list-toolbar">
diff --git a/ui/app/components/login.js b/ui/app/components/login.js
index 0a47d58..2c96e0d 100644
--- a/ui/app/components/login.js
+++ b/ui/app/components/login.js
@@ -1,5 +1,4 @@
import React from 'react'
-import ReactDOM from 'react-dom'
import { FormGroup, ControlLabel, FormControl, HelpBlock, Button,
Checkbox, Glyphicon, Overlay, Tooltip, Alert } from 'react-bootstrap'
@@ -59,6 +58,7 @@ class Login extends React.Component {
this.onPassword2 = this.onPassword2.bind(this)
this.onInvite = this.onInvite.bind(this)
this.onSubmit = this.onSubmit.bind(this)
+ this.onKeyPress = this.onKeyPress.bind(this)
this.onRemember = this.onRemember.bind(this)
}
@@ -73,6 +73,19 @@ class Login extends React.Component {
}
}
+ componentDidUpdate(prevProps, prevState) {
+ // If the user changes anything in the domain (which follows the @ sign)
+ // it gets replaced reverted to the domain name. This moves the cursor to
+ // before the @ sign when that happens
+ if (this.props.domain && this.state.username){
+ let textarea = this.usernameref
+ let start = this.state.username.indexOf('@')
+ if (textarea.selectionStart > start) {
+ textarea.setSelectionRange(start, start)
+ }
+ }
+ }
+
render () {
let rememberCheck = ""
let submitButton = ""
@@ -147,10 +160,11 @@ class Login extends React.Component {
<FormGroup controlId="loginPassword2" validationState={this.state.password2State}>
<ControlLabel>Repeat Password</ControlLabel>
<FormControl
- type="password"
- ref="password"
- value={this.state.password2 || ""}
- onChange={this.onPassword2} />
+ type="password"
+ inputRef={ref => this.password2ref = ref}
+ value={this.state.password2 || ""}
+ onChange={this.onPassword2}
+ />
{this.state.password2State == 'success' ? null : <FormControl.Feedback/>}
{password2Help}
</FormGroup>
@@ -161,8 +175,10 @@ class Login extends React.Component {
<FormGroup controlId="invite" validationState={this.state.inviteState}>
<ControlLabel>Invite Code</ControlLabel>
<FormControl
- value={this.state.invite || ""}
- onChange={this.onInvite} />
+ value={this.state.invite || ""}
+ onChange={this.onInvite}
+ inputRef={ref => this.inviteref = ref}
+ />
{inviteHelp}
</FormGroup>
)
@@ -175,64 +191,54 @@ class Login extends React.Component {
disabled: !this.maySubmit()
}
if (this.state.loading) {
- submitButton = <Button block {...buttonProps}><Spinner /></Button>
+ submitButton = <Button block {...buttonProps}><Spinner /></Button>
} else {
- submitButton = <Button block {...buttonProps}>{buttonText}</Button>
+ submitButton = <Button block {...buttonProps}>{buttonText}</Button>
}
-
- let usernameref = null
let usernameDisabled = false
let usernameValue = this.state.username || ""
if (this.props.address) {
usernameDisabled = true
usernameValue = this.props.address
- } else if (this.props.domain) {
- usernameref = function(c) {
- if (c != null) {
- let textarea = ReactDOM.findDOMNode(c)
- let start = textarea.value.indexOf('@')
- if (textarea.selectionStart > start) {
- textarea.setSelectionRange(start, start)
- }
- }
- }
}
+ const form = (
+ <form onSubmit={this.onSubmit} onKeyPress={this.onKeyPress}>
+ {message}
+ <FormGroup style={{marginBottom: '10px' }} controlId="loginUsername" validationState={this.state.usernameState}>
+ <ControlLabel>Username</ControlLabel>
+ <FormControl
+ componentClass="textarea"
+ style={{resize: "none"}}
+ rows="1"
+ inputRef={(ref) => this.usernameref = ref}
+ autoFocus
+ value={usernameValue}
+ disabled={usernameDisabled}
+ onChange={this.onUsernameChange}
+ onBlur={this.onUsernameBlur}
+ />
+ {this.state.usernameState == 'success' ? null : <FormControl.Feedback/>}
+ {usernameHelp}
+ </FormGroup>
- let form = <form onSubmit={this.onSubmit}>
- {message}
- <FormGroup style={{marginBottom: '10px' }} controlId="loginUsername" validationState={this.state.usernameState}>
- <ControlLabel>Username</ControlLabel>
- <FormControl
- componentClass="textarea"
- style={{resize: "none"}}
- rows="1"
- ref={usernameref}
- autoFocus
- value={usernameValue}
- disabled={usernameDisabled}
- onChange={this.onUsernameChange}
- onBlur={this.onUsernameBlur} />
- {this.state.usernameState == 'success' ? null : <FormControl.Feedback/>}
- {usernameHelp}
- </FormGroup>
-
- <FormGroup controlId="loginPassword" validationState={this.state.passwordState}>
- <ControlLabel>Password</ControlLabel>
- <FormControl
- type="password"
- ref="password"
- value={this.state.password || ""}
- onChange={this.onPassword} />
- {this.state.passwordState == 'success' ? null : <FormControl.Feedback/>}
- {passwordHelp}
- </FormGroup>
-
- {password2Elem}
- {inviteElem}
- {submitButton}
- {rememberCheck}
- </form>
+ <FormGroup controlId="loginPassword" validationState={this.state.passwordState}>
+ <ControlLabel>Password</ControlLabel>
+ <FormControl
+ type="password"
+ inputRef={ref => this.passwordref = ref}
+ value={this.state.password || ""}
+ onChange={this.onPassword}
+ />
+ {this.state.passwordState == 'success' ? null : <FormControl.Feedback/>}
+ {passwordHelp}
+ </FormGroup>
+ {password2Elem}
+ {inviteElem}
+ {submitButton}
+ {rememberCheck}
+ </form>
+ )
return form
}
@@ -390,6 +396,33 @@ class Login extends React.Component {
}
}
+ /**
+ * Handle key presses
+ */
+ onKeyPress(e) {
+ // On "Enter", move the focus to the first mounted but unfilled field,
+ // or submit the form if there are none.
+ if (e.key === 'Enter') {
+ // Ignore the @ and domain when checking the username
+ if (this.usernameref.value.split('@')[0] === ''){
+ this.usernameref.focus()
+ return
+ }
+
+ const firstUnfilledField = [
+ this.passwordref,
+ this.password2ref,
+ this.inviteref,
+ ].find(ref => ref != null && ref.value == "")
+
+ if (firstUnfilledField) {
+ firstUnfilledField.focus()
+ } else {
+ this.onSubmit(e);
+ }
+ }
+ }
+
doLogin() {
let account = Account.findOrAdd(this.state.username)
account.login(this.state.password, this.props.autoAllowed).then(
@@ -451,4 +484,4 @@ class Login extends React.Component {
}
-export default Login \ No newline at end of file
+export default Login
diff --git a/ui/app/components/main_panel/user_password_form.js b/ui/app/components/main_panel/user_password_form.js
index 5e26b19..33640f0 100644
--- a/ui/app/components/main_panel/user_password_form.js
+++ b/ui/app/components/main_panel/user_password_form.js
@@ -26,6 +26,7 @@ export default class UserPasswordForm extends React.Component {
repeatPassword: null
}
this.submit = this.submit.bind(this)
+ this.onKeyPress = this.onKeyPress.bind(this)
this.setNew = this.setNew.bind(this)
this.setCurrent = this.setCurrent.bind(this)
this.setRepeat = this.setRepeat.bind(this)
@@ -79,6 +80,22 @@ export default class UserPasswordForm extends React.Component {
)
}
+ onKeyPress(e) {
+ if (e.key === 'Enter') {
+ const firstUnfilledField = [
+ this.currentPasswordRef,
+ this.newPasswordRef,
+ this.repeatPasswordRef,
+ ].find(ref => ref != null && ref.value == "")
+
+ if (firstUnfilledField) {
+ firstUnfilledField.focus()
+ } else {
+ this.submit(e);
+ }
+ }
+ }
+
render () {
let submitButton = null
let message = null
@@ -100,21 +117,30 @@ export default class UserPasswordForm extends React.Component {
submitButton = <Button block disabled={!this.maySubmit()} onClick={this.submit}>Change</Button>
}
return (
- <form onSubmit={this.submit}>
+ <form onSubmit={this.submit} onKeyPress={this.onKeyPress}>
{message}
- <PasswordField id={this.props.account.id + "-current-password"}
- label="Current Password"
- validationMode="none"
- onChange={this.setCurrent} />
- <PasswordField id={this.props.account.id + "-new-password"}
- label="New Password"
- validationMode="crack"
- onChange={this.setNew} />
- <PasswordField id={this.props.account.id + "-repeat-password"}
- label="Repeat Password"
- validationMode="match"
- matchText={this.state.newPassword}
- onChange={this.setRepeat} />
+ <PasswordField
+ id={this.props.account.id + "-current-password"}
+ inputRef={ref => this.currentPasswordRef = ref}
+ label="Current Password"
+ validationMode="none"
+ onChange={this.setCurrent}
+ />
+ <PasswordField
+ id={this.props.account.id + "-new-password"}
+ inputRef={ref => this.newPasswordRef = ref}
+ label="New Password"
+ validationMode="crack"
+ onChange={this.setNew}
+ />
+ <PasswordField
+ id={this.props.account.id + "-repeat-password"}
+ inputRef={ref => this.repeatPasswordRef = ref}
+ label="Repeat Password"
+ validationMode="match"
+ matchText={this.state.newPassword}
+ onChange={this.setRepeat}
+ />
{submitButton}
</form>
)
diff --git a/ui/app/components/password_field.js b/ui/app/components/password_field.js
index 8397967..654b8a5 100644
--- a/ui/app/components/password_field.js
+++ b/ui/app/components/password_field.js
@@ -8,13 +8,16 @@ import Validate from 'lib/validate'
export default class PasswordField extends React.Component {
- static get defaultProps() {return{
- id: null, // required. controlId of the element
- label: "Password",
- onChange: null, // callback passed current password
- validationMode: "crack", // one of 'none', 'match', 'crack'
- matchText: null, // used if validationMode == 'match'
- }}
+ static get defaultProps() {
+ return {
+ id: null, // required. controlId of the element
+ label: "Password",
+ onChange: null, // callback passed current password
+ validationMode: "crack", // one of 'none', 'match', 'crack'
+ matchText: null, // used if validationMode == 'match'
+ inputRef: null, // a ref to the input. Used to set focus
+ }
+ }
constructor(props) {
super(props)
@@ -43,14 +46,15 @@ export default class PasswordField extends React.Component {
<FormGroup controlId={this.props.id} validationState={this.state.passwordState}>
<ControlLabel>{this.props.label}</ControlLabel>
<FormControl
- type="password"
- ref="password"
- value={this.state.password || ""}
- onChange={this.keypress} />
+ type="password"
+ inputRef={this.props.inputRef}
+ value={this.state.password || ""}
+ onChange={this.keypress}
+ />
{this.state.passwordState == 'success' ? null : <FormControl.Feedback/>}
{passwordHelp}
</FormGroup>
- )
+ )
}
keypress(e) {
diff --git a/ui/app/components/wizard/provider_select_stage.js b/ui/app/components/wizard/provider_select_stage.js
index 2a342d9..b19fc8a 100644
--- a/ui/app/components/wizard/provider_select_stage.js
+++ b/ui/app/components/wizard/provider_select_stage.js
@@ -33,12 +33,13 @@ export default class ProviderSelectStage extends React.Component {
provider: null, // Provider object, if selected
error: null // error message
}
- this.add = this.add.bind(this)
- this.remove = this.remove.bind(this)
- this.select = this.select.bind(this)
- this.close = this.close.bind(this)
- this.cancel = this.cancel.bind(this)
- this.next = this.next.bind(this)
+ this.add = this.add.bind(this)
+ this.remove = this.remove.bind(this)
+ this.select = this.select.bind(this)
+ this.close = this.close.bind(this)
+ this.cancel = this.cancel.bind(this)
+ this.next = this.next.bind(this)
+ this.onKeyDown = this.onKeyDown.bind(this)
}
componentWillMount() {
@@ -134,6 +135,13 @@ export default class ProviderSelectStage extends React.Component {
})
}
+ onKeyDown(e) {
+ // Check for enter key
+ if (e.keyCode === 13) {
+ this.next();
+ }
+ }
+
render() {
let modal = null
let info = null
@@ -171,9 +179,15 @@ export default class ProviderSelectStage extends React.Component {
</ButtonToolbar>
</div>
)
- let editlist = <ListEditor ref="list" items={this.state.domains}
- selected={this.state.selected} onRemove={this.remove} onAdd={this.add}
- onSelect={this.select} />
+ let editlist = <ListEditor
+ ref="list"
+ items={this.state.domains}
+ selected={this.state.selected}
+ onRemove={this.remove}
+ onAdd={this.add}
+ onSelect={this.select}
+ onKeyDown={this.onKeyDown}
+ />
return(
<StageLayout title={this.props.title} subtitle={this.props.subtitle} buttons={buttons}>
<HorizontalLayout equalWidths={true}>