2020-05-01 05:54:12 +03:00
|
|
|
import React, { Component } from 'react';
|
2020-08-15 01:04:38 +03:00
|
|
|
import { cite } from '~/logic/lib/util';
|
|
|
|
import { Spinner } from '~/views/components/Spinner';
|
2020-05-01 05:54:12 +03:00
|
|
|
|
|
|
|
export class Input extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
awaiting: false,
|
|
|
|
type: 'Sending to Dojo'
|
|
|
|
};
|
|
|
|
this.keyPress = this.keyPress.bind(this);
|
|
|
|
this.inputRef = React.createRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
2020-08-18 02:15:35 +03:00
|
|
|
if (
|
|
|
|
!document.activeElement == document.body
|
|
|
|
|| document.activeElement == this.inputRef.current
|
|
|
|
) {
|
|
|
|
this.inputRef.current.focus();
|
2020-05-01 05:54:12 +03:00
|
|
|
this.inputRef.current.setSelectionRange(this.props.cursor, this.props.cursor);
|
|
|
|
}
|
2020-08-18 02:15:35 +03:00
|
|
|
}
|
2020-05-01 05:54:12 +03:00
|
|
|
|
2020-08-18 02:15:35 +03:00
|
|
|
keyPress(e) {
|
2020-05-01 05:54:12 +03:00
|
|
|
if ((e.getModifierState('Control') || event.getModifierState('Meta'))
|
|
|
|
&& e.key === 'v') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
const allowedKeys = [
|
|
|
|
'Enter', 'Backspace', 'ArrowLeft', 'ArrowRight', 'Tab'
|
|
|
|
];
|
|
|
|
|
|
|
|
if ((e.key.length > 1) && (!(allowedKeys.includes(e.key)))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-18 02:15:35 +03:00
|
|
|
// submit on enter
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
this.setState({ awaiting: true, type: 'Sending to Dojo' });
|
|
|
|
this.props.api.soto('ret').then(() => {
|
|
|
|
this.setState({ awaiting: false });
|
|
|
|
});
|
|
|
|
} else if ((e.key === 'Backspace') && (this.props.cursor > 0)) {
|
|
|
|
this.props.store.doEdit({ del: this.props.cursor - 1 });
|
|
|
|
return this.props.store.setState({ cursor: this.props.cursor - 1 });
|
|
|
|
} else if (e.key === 'Backspace') {
|
|
|
|
return;
|
|
|
|
} else if (e.key.startsWith('Arrow')) {
|
|
|
|
if (e.key === 'ArrowLeft') {
|
|
|
|
if (this.props.cursor > 0) {
|
|
|
|
this.props.store.setState({ cursor: this.props.cursor - 1 });
|
|
|
|
}
|
|
|
|
} else if (e.key === 'ArrowRight') {
|
|
|
|
if (this.props.cursor < this.props.input.length) {
|
|
|
|
this.props.store.setState({ cursor: this.props.cursor + 1 });
|
|
|
|
}
|
2020-05-01 05:54:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-18 02:15:35 +03:00
|
|
|
// tab completion
|
|
|
|
else if (e.key === 'Tab') {
|
|
|
|
this.setState({ awaiting: true, type: 'Getting suggestions' });
|
|
|
|
this.props.api.soto({ tab: this.props.cursor }).then(() => {
|
|
|
|
this.setState({ awaiting: false });
|
|
|
|
});
|
|
|
|
}
|
2020-05-01 05:54:12 +03:00
|
|
|
|
2020-08-18 02:15:35 +03:00
|
|
|
// capture and transmit most characters
|
|
|
|
else {
|
|
|
|
this.props.store.doEdit({ ins: { cha: e.key, at: this.props.cursor } });
|
|
|
|
this.props.store.setState({ cursor: this.props.cursor + 1 });
|
|
|
|
}
|
2020-05-01 05:54:12 +03:00
|
|
|
}
|
|
|
|
|
2020-08-18 02:15:35 +03:00
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<div className="flex flex-row flex-grow-1 relative">
|
2020-08-19 06:10:36 +03:00
|
|
|
<div className="flex-shrink-0"><span class="dn-s">{cite(this.props.ship)}:</span>dojo
|
2020-08-18 02:15:35 +03:00
|
|
|
</div>
|
|
|
|
<span id="prompt">
|
|
|
|
{this.props.prompt}
|
|
|
|
</span>
|
|
|
|
<input
|
|
|
|
autoFocus
|
|
|
|
autocorrect="off"
|
|
|
|
autocapitalize="off"
|
|
|
|
spellcheck="false"
|
|
|
|
tabindex="0"
|
|
|
|
wrap="off"
|
|
|
|
className="mono ml1 flex-auto dib w-100"
|
|
|
|
id="dojo"
|
|
|
|
cursor={this.props.cursor}
|
|
|
|
onClick={e => this.props.store.setState({ cursor: e.target.selectionEnd })}
|
|
|
|
onKeyDown={this.keyPress}
|
|
|
|
onPaste={(e) => {
|
|
|
|
const clipboardData = e.clipboardData || window.clipboardData;
|
|
|
|
const paste = Array.from(clipboardData.getData('Text'));
|
|
|
|
paste.reduce(async (previous, next) => {
|
|
|
|
await previous;
|
|
|
|
this.setState({ cursor: this.props.cursor + 1 });
|
|
|
|
return this.props.store.doEdit({ ins: { cha: next, at: this.props.cursor } });
|
|
|
|
}, Promise.resolve());
|
|
|
|
e.preventDefault();
|
|
|
|
}}
|
|
|
|
ref={this.inputRef}
|
|
|
|
defaultValue={this.props.input}
|
|
|
|
/>
|
|
|
|
<Spinner awaiting={this.state.awaiting} text={`${this.state.type}...`} classes="absolute right-0 bottom-0 inter pa ba pa2 b--gray1-d" />
|
2020-05-01 05:54:12 +03:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default Input;
|