Search command is now built into findbar

This commit is contained in:
Cássio Zen 2016-07-07 16:56:12 -03:00
parent 3b316f1034
commit 26a51807f6
3 changed files with 83 additions and 34 deletions

View File

@ -47,9 +47,21 @@
cursor: default; cursor: default;
} }
.command .faded {
font-style: italic;
font-weight: lighter;
color: #555;
}
.highlightedCommand { .highlightedCommand {
color: white; color: white;
background: hsl(200, 50%, 50%); background: hsl(200, 50%, 50%);
padding: 2px 6px; padding: 2px 6px;
cursor: default; cursor: default;
} }
.highlightedCommand .faded {
font-style: italic;
font-weight: lighter;
color: #ddd;
}

View File

@ -3,12 +3,16 @@ import fuzzy from 'fuzzy';
import _ from 'lodash'; import _ from 'lodash';
import { runCommand } from '../actions/findbar'; import { runCommand } from '../actions/findbar';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Icon } from '../components/UI';
import styles from './FindBar.css'; import styles from './FindBar.css';
const SEARCH = 'SEARCH';
class FindBar extends Component { class FindBar extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this._compiledCommands = {}; this._compiledCommands = [];
this._searchCommand = { search: true, regexp:`(?:${SEARCH})?(.*)`, param:{ name:'searchTerm', display:'' } };
this.state = { this.state = {
value: '', value: '',
placeholder: '', placeholder: '',
@ -66,12 +70,6 @@ class FindBar extends Component {
param = { name:match[1], display:match[2] || this._camelCaseToSpace(match[1]) }; param = { name:match[1], display:match[2] || this._camelCaseToSpace(match[1]) };
} }
console.log(Object.assign({}, command, {
regexp,
token,
param
}));
return Object.assign({}, command, { return Object.assign({}, command, {
regexp, regexp,
token, token,
@ -84,17 +82,25 @@ class FindBar extends Component {
matchCommand() { matchCommand() {
const string = this.state.activeScope ? this.state.activeScope + this.state.value : this.state.value; const string = this.state.activeScope ? this.state.activeScope + this.state.value : this.state.value;
let match; let match;
const command = this._compiledCommands.find(command => { let command = this._compiledCommands.find(command => {
match = string.match(RegExp(`^${command.regexp}`, 'i')); match = string.match(RegExp(`^${command.regexp}`, 'i'));
return match; return match;
}); });
const paramName = command.param ? command.param.name : null; // If no command was found, trigger a search command
const enteredParamValue = command.param && match[1] ? match[1].trim() : null;
if (!command) { if (!command) {
// No matched command command = this._searchCommand;
return null; match = string.match(RegExp(`^${this._searchCommand.regexp}`, 'i'));
}
const paramName = command && command.param ? command.param.name : null;
const enteredParamValue = command && command.param && match[1] ? match[1].trim() : null;
if (command.search) {
this.setState({
activeScope: SEARCH
});
this.props.dispatch(runCommand('search', { searchTerm: enteredParamValue }));
} else if (command.param && !enteredParamValue) { } else if (command.param && !enteredParamValue) {
// Partial Match // Partial Match
// Command was partially matched: It requires a param, but param wasn't entered // Command was partially matched: It requires a param, but param wasn't entered
@ -128,12 +134,23 @@ class FindBar extends Component {
// Memoized version // Memoized version
_getSuggestions(value, scope, commands) { _getSuggestions(value, scope, commands) {
if (scope) return []; // No autocomplete for scoped input if (scope) return []; // No autocomplete for scoped input
const results = fuzzy.filter(value, commands, { const results = fuzzy.filter(value, commands, {
//pre: '<strong>', pre: '<strong>',
//post: '</strong>', post: '</strong>',
extract: el => el.token extract: el => el.token
}); });
return results.slice(0, 5).map(result => result.original);
let returnResults;
if (value.length > 0) {
returnResults = results.slice(0, 4).map(result => Object.assign({}, result.original, { string:result.string }));
returnResults.push(this._searchCommand);
}
else {
returnResults = results.slice(0, 5).map(result => Object.assign({}, result.original, { string:result.string }));
}
return returnResults;
} }
handleKeyDown(event) { handleKeyDown(event) {
@ -172,7 +189,7 @@ class FindBar extends Component {
isOpen: false, isOpen: false,
highlightedIndex: 0 highlightedIndex: 0
}; };
if (command) { if (command && !command.search) {
newState.value = command.token; newState.value = command.token;
} }
this.setState(newState, () => { this.setState(newState, () => {
@ -228,11 +245,14 @@ class FindBar extends Component {
} }
selectCommandFromMouse(command) { selectCommandFromMouse(command) {
this.setState({ const newState = {
value: command.token,
isOpen: false, isOpen: false,
highlightedIndex: 0 highlightedIndex: 0
}, () => { };
if (command && !command.search) {
newState.value = command.token;
}
this.setState(newState, () => {
this.matchCommand(); this.matchCommand();
this._input.focus(); this._input.focus();
this.setIgnoreBlur(false); this.setIgnoreBlur(false);
@ -245,23 +265,43 @@ class FindBar extends Component {
renderMenu() { renderMenu() {
const commands = this.getSuggestions().map((command, index) => { const commands = this.getSuggestions().map((command, index) => {
return ( if (!command.search) {
<div return (
className={this.state.highlightedIndex === index ? styles.highlightedCommand : styles.command} <div
key={command.token.trim().replace(/[^a-z0-9]+/gi, '-')} className={this.state.highlightedIndex === index ? styles.highlightedCommand : styles.command}
onMouseDown={() => this.setIgnoreBlur(true)} key={command.token.trim().replace(/[^a-z0-9]+/gi, '-')}
onMouseEnter={() => this.highlightCommandFromMouse(index)} onMouseDown={() => this.setIgnoreBlur(true)}
onClick={() => this.selectCommandFromMouse(command)} onMouseEnter={() => this.highlightCommandFromMouse(index)}
ref={`command-${index}`} onClick={() => this.selectCommandFromMouse(command)}
>{command.token}</div> >
); <Icon type="right-open-mini"/>
<span dangerouslySetInnerHTML={{__html: command.string}} />
</div>
);
} else {
return (
<div
className={this.state.highlightedIndex === index ? styles.highlightedCommand : styles.command}
key='builtin-search'
onMouseDown={() => this.setIgnoreBlur(true)}
onMouseEnter={() => this.highlightCommandFromMouse(index)}
onClick={() => this.selectCommandFromMouse(command)}
>
<span className={styles.faded}><Icon type="search"/> Search for: </span>{this.state.value}
</div>
);
}
}); });
return commands.length > 0 ? <div className={styles.menu} children={commands} /> : null; return commands.length > 0 ? <div className={styles.menu} children={commands} /> : null;
} }
renderActiveScope() { renderActiveScope() {
return <div className={styles.inputScope}>{this.state.activeScope}</div>; if (this.state.activeScope === SEARCH) {
return <div className={styles.inputScope}><Icon type="search"/> </div>;
} else {
return <div className={styles.inputScope}>{this.state.activeScope}</div>;
}
} }
render() { render() {

View File

@ -10,10 +10,7 @@ const commands = [
{ pattern: 'Create new FAQ item(:faqName as FAQ item name)' }, { pattern: 'Create new FAQ item(:faqName as FAQ item name)' },
{ pattern: 'Add news item(:headline)' }, { pattern: 'Add news item(:headline)' },
{ pattern: 'Add new User(:userName as User name)' }, { pattern: 'Add new User(:userName as User name)' },
{ pattern: 'Search(:searchTerm as what?)' },
{ pattern: 'Go to Settings' }, { pattern: 'Go to Settings' },
{ pattern: 'Find(:seachTerm as what?)' },
{ pattern: '(:searchTerm as Find...)', token:'Find' }
]; ];
storiesOf('FindBar', module) storiesOf('FindBar', module)