2017-06-06 23:19:12 +02:00
|
|
|
import React from "react";
|
|
|
|
import lbryuri from "lbryuri.js";
|
|
|
|
import { Icon } from "component/common.js";
|
2017-05-04 05:44:08 +02:00
|
|
|
|
|
|
|
class WunderBar extends React.PureComponent {
|
2017-06-06 23:19:12 +02:00
|
|
|
static TYPING_TIMEOUT = 800;
|
2017-05-12 01:28:43 +02:00
|
|
|
|
2017-05-04 05:44:08 +02:00
|
|
|
static propTypes = {
|
|
|
|
onSearch: React.PropTypes.func.isRequired,
|
2017-06-06 23:19:12 +02:00
|
|
|
onSubmit: React.PropTypes.func.isRequired,
|
|
|
|
};
|
2017-05-04 05:44:08 +02:00
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this._userTypingTimer = null;
|
2017-05-12 01:28:43 +02:00
|
|
|
this._isSearchDispatchPending = false;
|
2017-05-04 05:44:08 +02:00
|
|
|
this._input = null;
|
|
|
|
this._stateBeforeSearch = null;
|
|
|
|
this._resetOnNextBlur = true;
|
|
|
|
this.onChange = this.onChange.bind(this);
|
|
|
|
this.onFocus = this.onFocus.bind(this);
|
|
|
|
this.onBlur = this.onBlur.bind(this);
|
|
|
|
this.onKeyPress = this.onKeyPress.bind(this);
|
|
|
|
this.onReceiveRef = this.onReceiveRef.bind(this);
|
|
|
|
this.state = {
|
|
|
|
address: this.props.address,
|
2017-06-06 23:19:12 +02:00
|
|
|
icon: this.props.icon,
|
2017-05-04 05:44:08 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
if (this.userTypingTimer) {
|
|
|
|
clearTimeout(this._userTypingTimer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onChange(event) {
|
2017-06-06 23:19:12 +02:00
|
|
|
if (this._userTypingTimer) {
|
2017-05-04 05:44:08 +02:00
|
|
|
clearTimeout(this._userTypingTimer);
|
|
|
|
}
|
|
|
|
|
2017-06-06 23:19:12 +02:00
|
|
|
this.setState({ address: event.target.value });
|
2017-05-04 05:44:08 +02:00
|
|
|
|
2017-05-12 01:28:43 +02:00
|
|
|
this._isSearchDispatchPending = true;
|
|
|
|
|
2017-05-10 03:33:13 +02:00
|
|
|
let searchQuery = event.target.value;
|
2017-05-04 05:44:08 +02:00
|
|
|
|
|
|
|
this._userTypingTimer = setTimeout(() => {
|
2017-05-10 03:33:13 +02:00
|
|
|
const hasQuery = searchQuery.length === 0;
|
|
|
|
this._resetOnNextBlur = hasQuery;
|
2017-05-12 01:28:43 +02:00
|
|
|
this._isSearchDispatchPending = false;
|
2017-05-10 03:33:13 +02:00
|
|
|
if (searchQuery) {
|
|
|
|
this.props.onSearch(searchQuery);
|
|
|
|
}
|
2017-05-12 01:28:43 +02:00
|
|
|
}, WunderBar.TYPING_TIMEOUT); // 800ms delay, tweak for faster/slower
|
2017-05-04 05:44:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
componentWillReceiveProps(nextProps) {
|
2017-06-06 23:19:12 +02:00
|
|
|
if (
|
|
|
|
nextProps.viewingPage !== this.props.viewingPage ||
|
|
|
|
nextProps.address != this.props.address
|
|
|
|
) {
|
2017-05-04 05:44:08 +02:00
|
|
|
this.setState({ address: nextProps.address, icon: nextProps.icon });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onFocus() {
|
|
|
|
this._stateBeforeSearch = this.state;
|
|
|
|
let newState = {
|
|
|
|
icon: "icon-search",
|
2017-06-06 23:19:12 +02:00
|
|
|
isActive: true,
|
|
|
|
};
|
2017-05-04 05:44:08 +02:00
|
|
|
|
|
|
|
this._focusPending = true;
|
|
|
|
//below is hacking, improved when we have proper routing
|
2017-06-06 23:19:12 +02:00
|
|
|
if (
|
|
|
|
!this.state.address.startsWith("lbry://") &&
|
|
|
|
this.state.icon !== "icon-search"
|
|
|
|
) {
|
|
|
|
//onFocus, if they are not on an exact URL or a search page, clear the bar
|
|
|
|
newState.address = "";
|
2017-05-04 05:44:08 +02:00
|
|
|
}
|
|
|
|
this.setState(newState);
|
|
|
|
}
|
|
|
|
|
|
|
|
onBlur() {
|
2017-05-12 01:28:43 +02:00
|
|
|
if (this._isSearchDispatchPending) {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.onBlur();
|
2017-06-06 23:19:12 +02:00
|
|
|
}, WunderBar.TYPING_TIMEOUT + 1);
|
2017-05-04 05:44:08 +02:00
|
|
|
} else {
|
2017-06-06 23:19:12 +02:00
|
|
|
let commonState = { isActive: false };
|
2017-05-12 01:28:43 +02:00
|
|
|
if (this._resetOnNextBlur) {
|
|
|
|
this.setState(Object.assign({}, this._stateBeforeSearch, commonState));
|
|
|
|
this._input.value = this.state.address;
|
2017-06-06 23:19:12 +02:00
|
|
|
} else {
|
2017-05-12 01:28:43 +02:00
|
|
|
this._resetOnNextBlur = true;
|
|
|
|
this._stateBeforeSearch = this.state;
|
|
|
|
this.setState(commonState);
|
|
|
|
}
|
2017-05-04 05:44:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
2017-05-12 20:36:44 +02:00
|
|
|
if (this._input) {
|
|
|
|
const start = this._input.selectionStart,
|
|
|
|
end = this._input.selectionEnd;
|
|
|
|
|
|
|
|
this._input.value = this.state.address; //this causes cursor to go to end of input
|
|
|
|
|
|
|
|
this._input.setSelectionRange(start, end);
|
|
|
|
|
|
|
|
if (this._focusPending) {
|
|
|
|
this._input.select();
|
|
|
|
this._focusPending = false;
|
|
|
|
}
|
2017-05-04 05:44:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onKeyPress(event) {
|
|
|
|
if (event.charCode == 13 && this._input.value) {
|
|
|
|
let uri = null,
|
2017-06-06 23:19:12 +02:00
|
|
|
method = "onSubmit";
|
2017-05-04 05:44:08 +02:00
|
|
|
|
|
|
|
this._resetOnNextBlur = false;
|
|
|
|
clearTimeout(this._userTypingTimer);
|
|
|
|
|
|
|
|
try {
|
|
|
|
uri = lbryuri.normalize(this._input.value);
|
|
|
|
this.setState({ value: uri });
|
2017-06-06 23:19:12 +02:00
|
|
|
} catch (error) {
|
|
|
|
//then it's not a valid URL, so let's search
|
2017-05-04 05:44:08 +02:00
|
|
|
uri = this._input.value;
|
|
|
|
method = "onSearch";
|
|
|
|
}
|
|
|
|
|
|
|
|
this.props[method](uri);
|
|
|
|
this._input.blur();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onReceiveRef(ref) {
|
|
|
|
this._input = ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return (
|
2017-06-06 23:19:12 +02:00
|
|
|
<div
|
|
|
|
className={
|
|
|
|
"wunderbar" + (this.state.isActive ? " wunderbar--active" : "")
|
|
|
|
}
|
|
|
|
>
|
|
|
|
{this.state.icon ? <Icon fixed icon={this.state.icon} /> : ""}
|
|
|
|
<input
|
|
|
|
className="wunderbar__input"
|
|
|
|
type="search"
|
|
|
|
ref={this.onReceiveRef}
|
|
|
|
onFocus={this.onFocus}
|
|
|
|
onBlur={this.onBlur}
|
|
|
|
onChange={this.onChange}
|
|
|
|
onKeyPress={this.onKeyPress}
|
|
|
|
value={this.state.address}
|
|
|
|
placeholder={__("Find movies, music, games, and more")}
|
|
|
|
/>
|
2017-05-04 05:44:08 +02:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default WunderBar;
|