From 923678d74fd10dd5274b249de693dcb273e3039b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20Zen?= Date: Thu, 7 Jul 2016 12:04:19 -0300 Subject: [PATCH] Accepts command with no parameter --- .storybook/config.js | 2 +- src/actions/findbar.js | 4 +- src/containers/FindBar.js | 68 ++++++++++++++++++++----------- src/containers/stories/FindBar.js | 3 +- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/.storybook/config.js b/.storybook/config.js index e34ae993..21edff7e 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -1,7 +1,7 @@ import { configure } from '@kadira/storybook'; +import '../src/index.css'; function loadStories() { - require('../src/index.css'); require('../src/containers/stories/'); require('../src/components/stories/'); } diff --git a/src/actions/findbar.js b/src/actions/findbar.js index e8cd6917..91f38c30 100644 --- a/src/actions/findbar.js +++ b/src/actions/findbar.js @@ -1,5 +1,5 @@ export const RUN_COMMAND = 'RUN_COMMAND'; -export function runCommand(commandName, paramName, paramValue) { - return { type: RUN_COMMAND, command: commandName, payload: { [paramName]: paramValue } }; +export function runCommand(commandName, payload) { + return { type: RUN_COMMAND, command: commandName, payload }; } diff --git a/src/containers/FindBar.js b/src/containers/FindBar.js index 3d91e090..132a99ee 100644 --- a/src/containers/FindBar.js +++ b/src/containers/FindBar.js @@ -49,20 +49,29 @@ class FindBar extends Component { return result.charAt(0).toUpperCase() + result.slice(1); } + // Generates a regexp and splits a token and param details for a command compileCommand(command) { let regexp = ''; - let param; + let param = null; const matcher = /\(:([a-zA-Z_$][a-zA-Z0-9_$]*)(?:(?: as )(.*))?\)/g; const match = matcher.exec(command.pattern); - const token = command.pattern.slice(0, match.index) || command.token; - regexp += this._escapeRegExp(command.pattern.slice(0, match.index)); + const matchIndex = match ? match.index : command.pattern.length; - if (match[1]) { + const token = command.pattern.slice(0, matchIndex) || command.token; + regexp += this._escapeRegExp(command.pattern.slice(0, matchIndex)); + + if (match && match[1]) { regexp += '(.*)'; param = { name:match[1], display:match[2] || this._camelCaseToSpace(match[1]) }; } + console.log(Object.assign({}, command, { + regexp, + token, + param + })); + return Object.assign({}, command, { regexp, token, @@ -70,6 +79,8 @@ class FindBar extends Component { }); } + // Check if the entered string matches any command. + // adds a scope (so user can type param value) and dispatches action for fully matched commands matchCommand() { const string = this.state.activeScope ? this.state.activeScope + this.state.value : this.state.value; let match; @@ -78,18 +89,27 @@ class FindBar extends Component { return match; }); - const param = match[1] && match[1].trim(); + const paramName = command.param ? command.param.name : null; + const enteredParamValue = command.param && match[1] ? match[1].trim() : null; if (!command) { + // No matched command return null; - } else if (command && !param) { + } else if (command.param && !enteredParamValue) { + // Partial Match + // Command was partially matched: It requires a param, but param wasn't entered + // Set a scope so user can fill the param this.setState({ value: '', activeScope: command.token, placeholder: command.param.display }); } else { - this.props.dispatch(runCommand(command.token, command.param.name, param)); + // Match + // Command was matched and either it doesn't require a param or it's required param was entered + // Dispatch action + const payload = paramName ? { [paramName]: enteredParamValue } : null; + this.props.dispatch(runCommand(command.token, payload)); } } @@ -102,10 +122,18 @@ class FindBar extends Component { } } - handleChange(event) { - this.setState({ - value: event.target.value, + getSuggestions() { + return this._getSuggestions(this.state.value, this.state.activeScope, this._compiledCommands); + } + // Memoized version + _getSuggestions(value, scope, commands) { + if (scope) return []; // No autocomplete for scoped input + const results = fuzzy.filter(value, commands, { + //pre: '', + //post: '', + extract: el => el.token }); + return results.slice(0, 5).map(result => result.original); } handleKeyDown(event) { @@ -171,6 +199,12 @@ class FindBar extends Component { } } + handleChange(event) { + this.setState({ + value: event.target.value, + }); + } + handleInputBlur() { if (this._ignoreBlur) return; this.setState({ @@ -189,20 +223,6 @@ class FindBar extends Component { this.setState({ isOpen: true }); } - _getSuggestions(value, scope, commands) { - if (scope) return []; // TODO: Prepare for multiple params & search suggestions - const results = fuzzy.filter(value, commands, { - //pre: '', - //post: '', - extract: el => el.token - }); - return results.slice(0, 5).map(result => result.original); - } - - getSuggestions() { - return this._getSuggestions(this.state.value, this.state.activeScope, this._compiledCommands); - } - highlightCommandFromMouse(index) { this.setState({ highlightedIndex: index }); } diff --git a/src/containers/stories/FindBar.js b/src/containers/stories/FindBar.js index b512d61d..fbd5b580 100644 --- a/src/containers/stories/FindBar.js +++ b/src/containers/stories/FindBar.js @@ -10,7 +10,8 @@ const commands = [ { pattern: 'Create new FAQ item(:faqName as FAQ item name)' }, { pattern: 'Add news item(:headline)' }, { pattern: 'Add new User(:userName as User name)' }, - { pattern: 'Search(:seachTerm as what?)' }, + { pattern: 'Search(:searchTerm as what?)' }, + { pattern: 'Go to Settings' }, { pattern: 'Find(:seachTerm as what?)' }, { pattern: '(:searchTerm as Find...)', token:'Find' } ];