lbry-desktop/ui/js/component/wunderbar/view.jsx

177 lines
4.5 KiB
React
Raw Normal View History

2017-06-06 23:19:12 +02:00
import React from "react";
import lbryuri from "lbryuri.js";
import { Icon } from "component/common.js";
2017-07-17 08:06:04 +02:00
import { parseQueryParams } from "util/query_params";
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) {
2017-06-23 08:21:37 +02:00
this.props.onSearch(searchQuery.trim());
2017-05-10 03:33:13 +02:00
}
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-07-17 08:06:04 +02:00
method = "onSubmit",
extraParams = {};
2017-05-04 05:44:08 +02:00
this._resetOnNextBlur = false;
clearTimeout(this._userTypingTimer);
2017-07-17 08:06:04 +02:00
const parts = this._input.value.trim().split("?");
const value = parts.shift();
if (parts.length > 0) extraParams = parseQueryParams(parts.join(""));
2017-06-23 08:21:37 +02:00
2017-05-04 05:44:08 +02:00
try {
2017-06-23 08:21:37 +02:00
uri = lbryuri.normalize(value);
2017-05-04 05:44:08 +02:00
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-06-23 08:21:37 +02:00
uri = value;
2017-05-04 05:44:08 +02:00
method = "onSearch";
}
2017-07-17 08:06:04 +02:00
this.props[method](uri, extraParams);
2017-05-04 05:44:08 +02:00
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;